summaryrefslogtreecommitdiff
path: root/Source/JavaScriptCore/runtime
diff options
context:
space:
mode:
authorSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
committerSimon Hausmann <simon.hausmann@nokia.com>2012-01-06 14:44:00 +0100
commit40736c5763bf61337c8c14e16d8587db021a87d4 (patch)
treeb17a9c00042ad89cb1308e2484491799aa14e9f8 /Source/JavaScriptCore/runtime
downloadqtwebkit-40736c5763bf61337c8c14e16d8587db021a87d4.tar.gz
Imported WebKit commit 2ea9d364d0f6efa8fa64acf19f451504c59be0e4 (http://svn.webkit.org/repository/webkit/trunk@104285)
Diffstat (limited to 'Source/JavaScriptCore/runtime')
-rw-r--r--Source/JavaScriptCore/runtime/ArgList.cpp89
-rw-r--r--Source/JavaScriptCore/runtime/ArgList.h183
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.cpp352
-rw-r--r--Source/JavaScriptCore/runtime/Arguments.h177
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConstructor.cpp126
-rw-r--r--Source/JavaScriptCore/runtime/ArrayConstructor.h64
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.cpp1200
-rw-r--r--Source/JavaScriptCore/runtime/ArrayPrototype.h59
-rw-r--r--Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h56
-rw-r--r--Source/JavaScriptCore/runtime/BigInteger.h112
-rw-r--r--Source/JavaScriptCore/runtime/BooleanConstructor.cpp87
-rw-r--r--Source/JavaScriptCore/runtime/BooleanConstructor.h62
-rw-r--r--Source/JavaScriptCore/runtime/BooleanObject.cpp42
-rw-r--r--Source/JavaScriptCore/runtime/BooleanObject.h61
-rw-r--r--Source/JavaScriptCore/runtime/BooleanPrototype.cpp109
-rw-r--r--Source/JavaScriptCore/runtime/BooleanPrototype.h59
-rw-r--r--Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h101
-rw-r--r--Source/JavaScriptCore/runtime/CallData.cpp42
-rw-r--r--Source/JavaScriptCore/runtime/CallData.h64
-rw-r--r--Source/JavaScriptCore/runtime/ClassInfo.h198
-rw-r--r--Source/JavaScriptCore/runtime/CommonIdentifiers.cpp42
-rw-r--r--Source/JavaScriptCore/runtime/CommonIdentifiers.h154
-rw-r--r--Source/JavaScriptCore/runtime/Completion.cpp84
-rw-r--r--Source/JavaScriptCore/runtime/Completion.h39
-rw-r--r--Source/JavaScriptCore/runtime/ConstructData.cpp42
-rw-r--r--Source/JavaScriptCore/runtime/ConstructData.h63
-rw-r--r--Source/JavaScriptCore/runtime/DateConstructor.cpp229
-rw-r--r--Source/JavaScriptCore/runtime/DateConstructor.h66
-rw-r--r--Source/JavaScriptCore/runtime/DateConversion.cpp107
-rw-r--r--Source/JavaScriptCore/runtime/DateConversion.h63
-rw-r--r--Source/JavaScriptCore/runtime/DateInstance.cpp93
-rw-r--r--Source/JavaScriptCore/runtime/DateInstance.h97
-rw-r--r--Source/JavaScriptCore/runtime/DateInstanceCache.h93
-rw-r--r--Source/JavaScriptCore/runtime/DatePrototype.cpp1109
-rw-r--r--Source/JavaScriptCore/runtime/DatePrototype.h61
-rw-r--r--Source/JavaScriptCore/runtime/Error.cpp178
-rw-r--r--Source/JavaScriptCore/runtime/Error.h132
-rw-r--r--Source/JavaScriptCore/runtime/ErrorConstructor.cpp76
-rw-r--r--Source/JavaScriptCore/runtime/ErrorConstructor.h60
-rw-r--r--Source/JavaScriptCore/runtime/ErrorInstance.cpp36
-rw-r--r--Source/JavaScriptCore/runtime/ErrorInstance.h75
-rw-r--r--Source/JavaScriptCore/runtime/ErrorPrototype.cpp138
-rw-r--r--Source/JavaScriptCore/runtime/ErrorPrototype.h61
-rw-r--r--Source/JavaScriptCore/runtime/ExceptionHelpers.cpp170
-rw-r--r--Source/JavaScriptCore/runtime/ExceptionHelpers.h114
-rw-r--r--Source/JavaScriptCore/runtime/Executable.cpp756
-rw-r--r--Source/JavaScriptCore/runtime/Executable.h716
-rw-r--r--Source/JavaScriptCore/runtime/FunctionConstructor.cpp133
-rw-r--r--Source/JavaScriptCore/runtime/FunctionConstructor.h66
-rw-r--r--Source/JavaScriptCore/runtime/FunctionPrototype.cpp215
-rw-r--r--Source/JavaScriptCore/runtime/FunctionPrototype.h58
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallback.cpp54
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallback.h82
-rw-r--r--Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp110
-rw-r--r--Source/JavaScriptCore/runtime/GetterSetter.cpp48
-rw-r--r--Source/JavaScriptCore/runtime/GetterSetter.h85
-rw-r--r--Source/JavaScriptCore/runtime/Identifier.cpp288
-rw-r--r--Source/JavaScriptCore/runtime/Identifier.h258
-rw-r--r--Source/JavaScriptCore/runtime/InitializeThreading.cpp79
-rw-r--r--Source/JavaScriptCore/runtime/InitializeThreading.h40
-rw-r--r--Source/JavaScriptCore/runtime/InternalFunction.cpp81
-rw-r--r--Source/JavaScriptCore/runtime/InternalFunction.h69
-rw-r--r--Source/JavaScriptCore/runtime/Intrinsic.h52
-rw-r--r--Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp35
-rw-r--r--Source/JavaScriptCore/runtime/JSAPIValueWrapper.h78
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.cpp244
-rw-r--r--Source/JavaScriptCore/runtime/JSActivation.h145
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.cpp1379
-rw-r--r--Source/JavaScriptCore/runtime/JSArray.h293
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundFunction.cpp131
-rw-r--r--Source/JavaScriptCore/runtime/JSBoundFunction.h73
-rw-r--r--Source/JavaScriptCore/runtime/JSByteArray.cpp120
-rw-r--r--Source/JavaScriptCore/runtime/JSByteArray.h133
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.cpp223
-rw-r--r--Source/JavaScriptCore/runtime/JSCell.h344
-rw-r--r--Source/JavaScriptCore/runtime/JSChunk.cpp28
-rw-r--r--Source/JavaScriptCore/runtime/JSChunk.h31
-rw-r--r--Source/JavaScriptCore/runtime/JSDateMath.cpp267
-rw-r--r--Source/JavaScriptCore/runtime/JSDateMath.h169
-rw-r--r--Source/JavaScriptCore/runtime/JSExportMacros.h73
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.cpp362
-rw-r--r--Source/JavaScriptCore/runtime/JSFunction.h163
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.cpp528
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalData.h386
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.cpp482
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObject.h510
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp718
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h61
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalThis.cpp56
-rw-r--r--Source/JavaScriptCore/runtime/JSGlobalThis.h73
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.cpp263
-rw-r--r--Source/JavaScriptCore/runtime/JSLock.h108
-rw-r--r--Source/JavaScriptCore/runtime/JSNotAnObject.cpp95
-rw-r--r--Source/JavaScriptCore/runtime/JSNotAnObject.h86
-rw-r--r--Source/JavaScriptCore/runtime/JSONObject.cpp879
-rw-r--r--Source/JavaScriptCore/runtime/JSONObject.h68
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.cpp848
-rw-r--r--Source/JavaScriptCore/runtime/JSObject.h879
-rw-r--r--Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp110
-rw-r--r--Source/JavaScriptCore/runtime/JSPropertyNameIterator.h126
-rw-r--r--Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp95
-rw-r--r--Source/JavaScriptCore/runtime/JSStaticScopeObject.h84
-rw-r--r--Source/JavaScriptCore/runtime/JSString.cpp303
-rw-r--r--Source/JavaScriptCore/runtime/JSString.h478
-rw-r--r--Source/JavaScriptCore/runtime/JSStringBuilder.h194
-rw-r--r--Source/JavaScriptCore/runtime/JSType.h61
-rw-r--r--Source/JavaScriptCore/runtime/JSTypeInfo.h100
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.cpp231
-rw-r--r--Source/JavaScriptCore/runtime/JSValue.h478
-rw-r--r--Source/JavaScriptCore/runtime/JSValueInlineMethods.h498
-rw-r--r--Source/JavaScriptCore/runtime/JSVariableObject.cpp98
-rw-r--r--Source/JavaScriptCore/runtime/JSVariableObject.h173
-rw-r--r--Source/JavaScriptCore/runtime/JSWrapperObject.cpp41
-rw-r--r--Source/JavaScriptCore/runtime/JSWrapperObject.h72
-rw-r--r--Source/JavaScriptCore/runtime/LiteralParser.cpp829
-rw-r--r--Source/JavaScriptCore/runtime/LiteralParser.h166
-rw-r--r--Source/JavaScriptCore/runtime/Lookup.cpp96
-rw-r--r--Source/JavaScriptCore/runtime/Lookup.h384
-rw-r--r--Source/JavaScriptCore/runtime/MathObject.cpp246
-rw-r--r--Source/JavaScriptCore/runtime/MathObject.h58
-rw-r--r--Source/JavaScriptCore/runtime/MemoryStatistics.cpp50
-rw-r--r--Source/JavaScriptCore/runtime/MemoryStatistics.h45
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp79
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorConstructor.h80
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp46
-rw-r--r--Source/JavaScriptCore/runtime/NativeErrorPrototype.h49
-rw-r--r--Source/JavaScriptCore/runtime/NumberConstructor.cpp143
-rw-r--r--Source/JavaScriptCore/runtime/NumberConstructor.h68
-rw-r--r--Source/JavaScriptCore/runtime/NumberObject.cpp53
-rw-r--r--Source/JavaScriptCore/runtime/NumberObject.h55
-rw-r--r--Source/JavaScriptCore/runtime/NumberPrototype.cpp488
-rw-r--r--Source/JavaScriptCore/runtime/NumberPrototype.h58
-rw-r--r--Source/JavaScriptCore/runtime/NumericStrings.h98
-rw-r--r--Source/JavaScriptCore/runtime/ObjectConstructor.cpp415
-rw-r--r--Source/JavaScriptCore/runtime/ObjectConstructor.h63
-rw-r--r--Source/JavaScriptCore/runtime/ObjectPrototype.cpp223
-rw-r--r--Source/JavaScriptCore/runtime/ObjectPrototype.h66
-rw-r--r--Source/JavaScriptCore/runtime/Operations.cpp114
-rw-r--r--Source/JavaScriptCore/runtime/Operations.h392
-rw-r--r--Source/JavaScriptCore/runtime/Options.cpp214
-rw-r--r--Source/JavaScriptCore/runtime/Options.h84
-rw-r--r--Source/JavaScriptCore/runtime/PropertyDescriptor.cpp204
-rw-r--r--Source/JavaScriptCore/runtime/PropertyDescriptor.h82
-rw-r--r--Source/JavaScriptCore/runtime/PropertyMapHashTable.h591
-rw-r--r--Source/JavaScriptCore/runtime/PropertyNameArray.cpp55
-rw-r--r--Source/JavaScriptCore/runtime/PropertyNameArray.h99
-rw-r--r--Source/JavaScriptCore/runtime/PropertySlot.cpp44
-rw-r--r--Source/JavaScriptCore/runtime/PropertySlot.h241
-rw-r--r--Source/JavaScriptCore/runtime/Protect.h66
-rw-r--r--Source/JavaScriptCore/runtime/PutPropertySlot.h81
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.cpp486
-rw-r--r--Source/JavaScriptCore/runtime/RegExp.h116
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCache.cpp87
-rw-r--r--Source/JavaScriptCore/runtime/RegExpCache.h67
-rw-r--r--Source/JavaScriptCore/runtime/RegExpConstructor.cpp400
-rw-r--r--Source/JavaScriptCore/runtime/RegExpConstructor.h144
-rw-r--r--Source/JavaScriptCore/runtime/RegExpKey.h111
-rw-r--r--Source/JavaScriptCore/runtime/RegExpMatchesArray.h123
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.cpp272
-rw-r--r--Source/JavaScriptCore/runtime/RegExpObject.h117
-rw-r--r--Source/JavaScriptCore/runtime/RegExpPrototype.cpp161
-rw-r--r--Source/JavaScriptCore/runtime/RegExpPrototype.h58
-rw-r--r--Source/JavaScriptCore/runtime/SamplingCounter.cpp52
-rw-r--r--Source/JavaScriptCore/runtime/SamplingCounter.h178
-rw-r--r--Source/JavaScriptCore/runtime/ScopeChain.cpp85
-rw-r--r--Source/JavaScriptCore/runtime/ScopeChain.h169
-rw-r--r--Source/JavaScriptCore/runtime/ScopeChainMark.h30
-rw-r--r--Source/JavaScriptCore/runtime/SmallStrings.cpp127
-rw-r--r--Source/JavaScriptCore/runtime/SmallStrings.h85
-rw-r--r--Source/JavaScriptCore/runtime/StorageBarrier.h76
-rw-r--r--Source/JavaScriptCore/runtime/StrictEvalActivation.cpp50
-rw-r--r--Source/JavaScriptCore/runtime/StrictEvalActivation.h63
-rw-r--r--Source/JavaScriptCore/runtime/StringConstructor.cpp123
-rw-r--r--Source/JavaScriptCore/runtime/StringConstructor.h63
-rw-r--r--Source/JavaScriptCore/runtime/StringObject.cpp99
-rw-r--r--Source/JavaScriptCore/runtime/StringObject.h82
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.cpp1490
-rw-r--r--Source/JavaScriptCore/runtime/StringPrototype.h63
-rw-r--r--Source/JavaScriptCore/runtime/StringRecursionChecker.cpp38
-rw-r--r--Source/JavaScriptCore/runtime/StringRecursionChecker.h79
-rw-r--r--Source/JavaScriptCore/runtime/Structure.cpp851
-rw-r--r--Source/JavaScriptCore/runtime/Structure.h406
-rw-r--r--Source/JavaScriptCore/runtime/StructureChain.cpp57
-rw-r--r--Source/JavaScriptCore/runtime/StructureChain.h84
-rw-r--r--Source/JavaScriptCore/runtime/StructureTransitionTable.h172
-rw-r--r--Source/JavaScriptCore/runtime/SymbolTable.h133
-rw-r--r--Source/JavaScriptCore/runtime/Terminator.h47
-rw-r--r--Source/JavaScriptCore/runtime/TimeoutChecker.cpp142
-rw-r--r--Source/JavaScriptCore/runtime/TimeoutChecker.h74
-rw-r--r--Source/JavaScriptCore/runtime/Tracing.d40
-rw-r--r--Source/JavaScriptCore/runtime/Tracing.h50
-rw-r--r--Source/JavaScriptCore/runtime/UString.cpp475
-rw-r--r--Source/JavaScriptCore/runtime/UString.h288
-rw-r--r--Source/JavaScriptCore/runtime/UStringBuilder.h43
-rw-r--r--Source/JavaScriptCore/runtime/UStringConcatenate.h141
-rw-r--r--Source/JavaScriptCore/runtime/Uint16WithFraction.h270
-rw-r--r--Source/JavaScriptCore/runtime/WeakGCMap.h191
-rw-r--r--Source/JavaScriptCore/runtime/WeakRandom.h91
-rw-r--r--Source/JavaScriptCore/runtime/WriteBarrier.h231
199 files changed, 38293 insertions, 0 deletions
diff --git a/Source/JavaScriptCore/runtime/ArgList.cpp b/Source/JavaScriptCore/runtime/ArgList.cpp
new file mode 100644
index 000000000..873ddc2da
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ArgList.cpp
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "ArgList.h"
+
+#include "HeapRootVisitor.h"
+#include "JSValue.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
+
+using std::min;
+
+namespace JSC {
+
+void ArgList::getSlice(int startIndex, ArgList& result) const
+{
+ if (startIndex <= 0 || startIndex >= m_argCount) {
+ result = ArgList();
+ return;
+ }
+
+ result.m_args = m_args - startIndex;
+ result.m_argCount = m_argCount - startIndex;
+}
+
+void MarkedArgumentBuffer::markLists(HeapRootVisitor& heapRootVisitor, ListSet& markSet)
+{
+ ListSet::iterator end = markSet.end();
+ for (ListSet::iterator it = markSet.begin(); it != end; ++it) {
+ MarkedArgumentBuffer* list = *it;
+ for (int i = 0; i < list->m_size; ++i)
+ heapRootVisitor.visit(reinterpret_cast<JSValue*>(&list->slotFor(i)));
+ }
+}
+
+void MarkedArgumentBuffer::slowAppend(JSValue v)
+{
+ int newCapacity = m_capacity * 4;
+ EncodedJSValue* newBuffer = &(new EncodedJSValue[newCapacity])[newCapacity - 1];
+ for (int i = 0; i < m_capacity; ++i)
+ newBuffer[-i] = m_buffer[-i];
+
+ if (EncodedJSValue* base = mallocBase())
+ delete [] base;
+
+ m_buffer = newBuffer;
+ m_capacity = newCapacity;
+
+ slotFor(m_size) = JSValue::encode(v);
+ ++m_size;
+
+ if (m_markSet)
+ return;
+
+ // 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.
+ for (int i = 0; i < m_size; ++i) {
+ Heap* heap = Heap::heap(JSValue::decode(slotFor(i)));
+ if (!heap)
+ continue;
+
+ m_markSet = &heap->markListSet();
+ m_markSet->add(this);
+ break;
+ }
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArgList.h b/Source/JavaScriptCore/runtime/ArgList.h
new file mode 100644
index 000000000..ac5a4f271
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ArgList.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ArgList_h
+#define ArgList_h
+
+#include "CallFrame.h"
+#include "Register.h"
+#include "WriteBarrier.h"
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+ class SlotVisitor;
+
+ class MarkedArgumentBuffer {
+ WTF_MAKE_NONCOPYABLE(MarkedArgumentBuffer);
+ friend class JSGlobalData;
+ friend class ArgList;
+
+ private:
+ static const size_t inlineCapacity = 8;
+ typedef Vector<Register, inlineCapacity> VectorType;
+ typedef HashSet<MarkedArgumentBuffer*> ListSet;
+
+ public:
+ // Constructor for a read-write list, to which you may append values.
+ // FIXME: Remove all clients of this API, then remove this API.
+ MarkedArgumentBuffer()
+ : m_size(0)
+ , m_capacity(inlineCapacity)
+ , m_buffer(&m_inlineBuffer[m_capacity - 1])
+ , m_markSet(0)
+ {
+ }
+
+ ~MarkedArgumentBuffer()
+ {
+ if (m_markSet)
+ m_markSet->remove(this);
+
+ if (EncodedJSValue* base = mallocBase())
+ delete [] base;
+ }
+
+ size_t size() const { return m_size; }
+ bool isEmpty() const { return !m_size; }
+
+ JSValue at(int i) const
+ {
+ if (i >= m_size)
+ return jsUndefined();
+
+ return JSValue::decode(slotFor(i));
+ }
+
+ void clear()
+ {
+ m_size = 0;
+ }
+
+ void append(JSValue v)
+ {
+ if (m_size >= m_capacity)
+ return slowAppend(v);
+
+ slotFor(m_size) = JSValue::encode(v);
+ ++m_size;
+ }
+
+ void removeLast()
+ {
+ ASSERT(m_size);
+ m_size--;
+ }
+
+ JSValue last()
+ {
+ ASSERT(m_size);
+ return JSValue::decode(slotFor(m_size - 1));
+ }
+
+ static void markLists(HeapRootVisitor&, ListSet&);
+
+ private:
+ void slowAppend(JSValue);
+
+ EncodedJSValue& slotFor(int item) const
+ {
+ return m_buffer[-item];
+ }
+
+ EncodedJSValue* mallocBase()
+ {
+ if (m_capacity == static_cast<int>(inlineCapacity))
+ return 0;
+ return &slotFor(m_capacity - 1);
+ }
+
+ int m_size;
+ int m_capacity;
+ EncodedJSValue m_inlineBuffer[inlineCapacity];
+ EncodedJSValue* m_buffer;
+ ListSet* m_markSet;
+
+ private:
+ // Prohibits new / delete, which would break GC.
+ void* operator new(size_t size)
+ {
+ return fastMalloc(size);
+ }
+ void operator delete(void* p)
+ {
+ fastFree(p);
+ }
+
+ void* operator new[](size_t);
+ void operator delete[](void*);
+
+ void* operator new(size_t, void*);
+ void operator delete(void*, size_t);
+ };
+
+ class ArgList {
+ friend class JIT;
+ public:
+ ArgList()
+ : m_args(0)
+ , m_argCount(0)
+ {
+ }
+
+ ArgList(ExecState* exec)
+ : m_args(reinterpret_cast<JSValue*>(&exec[CallFrame::argumentOffset(0)]))
+ , m_argCount(exec->argumentCount())
+ {
+ }
+
+ ArgList(const MarkedArgumentBuffer& args)
+ : m_args(reinterpret_cast<JSValue*>(args.m_buffer))
+ , m_argCount(args.size())
+ {
+ }
+
+ JSValue at(int i) const
+ {
+ if (i >= m_argCount)
+ return jsUndefined();
+ return m_args[-i];
+ }
+
+ bool isEmpty() const { return !m_argCount; }
+ size_t size() const { return m_argCount; }
+
+ void getSlice(int startIndex, ArgList& result) const;
+
+ private:
+ JSValue* m_args;
+ int m_argCount;
+ };
+
+} // namespace JSC
+
+#endif // ArgList_h
diff --git a/Source/JavaScriptCore/runtime/Arguments.cpp b/Source/JavaScriptCore/runtime/Arguments.cpp
new file mode 100644
index 000000000..fc136eb7e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Arguments.cpp
@@ -0,0 +1,352 @@
+/*
+ * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2007 Maks Orlovich
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Arguments.h"
+
+#include "JSActivation.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+
+using namespace std;
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(Arguments);
+
+const ClassInfo Arguments::s_info = { "Arguments", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(Arguments) };
+
+void Arguments::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ Arguments* thisObject = jsCast<Arguments*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ JSObject::visitChildren(thisObject, visitor);
+
+ if (thisObject->d->registerArray)
+ visitor.appendValues(thisObject->d->registerArray.get(), thisObject->d->numArguments);
+ visitor.append(&thisObject->d->callee);
+ if (thisObject->d->activation)
+ visitor.append(&thisObject->d->activation);
+}
+
+void Arguments::destroy(JSCell* cell)
+{
+ jsCast<Arguments*>(cell)->Arguments::~Arguments();
+}
+
+void Arguments::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length)
+{
+ if (UNLIKELY(d->overrodeLength)) {
+ length = min(get(exec, exec->propertyNames().length).toUInt32(exec), length);
+ for (unsigned i = 0; i < length; i++)
+ callFrame->setArgument(i, get(exec, i));
+ return;
+ }
+ ASSERT(length == this->length(exec));
+ for (size_t i = 0; i < length; ++i) {
+ if (!d->deletedArguments || !d->deletedArguments[i])
+ callFrame->setArgument(i, argument(i).get());
+ else
+ callFrame->setArgument(i, get(exec, i));
+ }
+}
+
+void Arguments::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
+{
+ if (UNLIKELY(d->overrodeLength)) {
+ unsigned length = get(exec, exec->propertyNames().length).toUInt32(exec);
+ for (unsigned i = 0; i < length; i++)
+ args.append(get(exec, i));
+ return;
+ }
+ uint32_t length = this->length(exec);
+ for (size_t i = 0; i < length; ++i) {
+ if (!d->deletedArguments || !d->deletedArguments[i])
+ args.append(argument(i).get());
+ else
+ args.append(get(exec, i));
+ }
+}
+
+bool Arguments::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
+{
+ Arguments* thisObject = jsCast<Arguments*>(cell);
+ if (i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
+ slot.setValue(thisObject->argument(i).get());
+ return true;
+ }
+
+ return JSObject::getOwnPropertySlot(thisObject, exec, Identifier(exec, UString::number(i)), slot);
+}
+
+void Arguments::createStrictModeCallerIfNecessary(ExecState* exec)
+{
+ if (d->overrodeCaller)
+ return;
+
+ d->overrodeCaller = true;
+ PropertyDescriptor descriptor;
+ descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Getter | Setter);
+ methodTable()->defineOwnProperty(this, exec, exec->propertyNames().caller, descriptor, false);
+}
+
+void Arguments::createStrictModeCalleeIfNecessary(ExecState* exec)
+{
+ if (d->overrodeCallee)
+ return;
+
+ d->overrodeCallee = true;
+ PropertyDescriptor descriptor;
+ descriptor.setAccessorDescriptor(globalObject()->throwTypeErrorGetterSetter(exec), DontEnum | DontDelete | Getter | Setter);
+ methodTable()->defineOwnProperty(this, exec, exec->propertyNames().callee, descriptor, false);
+}
+
+bool Arguments::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ Arguments* thisObject = jsCast<Arguments*>(cell);
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
+ if (isArrayIndex && i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
+ slot.setValue(thisObject->argument(i).get());
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
+ slot.setValue(jsNumber(thisObject->d->numArguments));
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
+ if (!thisObject->d->isStrictMode) {
+ slot.setValue(thisObject->d->callee.get());
+ return true;
+ }
+ thisObject->createStrictModeCalleeIfNecessary(exec);
+ }
+
+ if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+ thisObject->createStrictModeCallerIfNecessary(exec);
+
+ return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+}
+
+bool Arguments::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ Arguments* thisObject = jsCast<Arguments*>(object);
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
+ if (isArrayIndex && i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
+ descriptor.setDescriptor(thisObject->argument(i).get(), None);
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().length && LIKELY(!thisObject->d->overrodeLength)) {
+ descriptor.setDescriptor(jsNumber(thisObject->d->numArguments), DontEnum);
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().callee && LIKELY(!thisObject->d->overrodeCallee)) {
+ if (!thisObject->d->isStrictMode) {
+ descriptor.setDescriptor(thisObject->d->callee.get(), DontEnum);
+ return true;
+ }
+ thisObject->createStrictModeCalleeIfNecessary(exec);
+ }
+
+ if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+ thisObject->createStrictModeCallerIfNecessary(exec);
+
+ return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+}
+
+void Arguments::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ Arguments* thisObject = jsCast<Arguments*>(object);
+ for (unsigned i = 0; i < thisObject->d->numArguments; ++i) {
+ if (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])
+ propertyNames.add(Identifier(exec, UString::number(i)));
+ }
+ if (mode == IncludeDontEnumProperties) {
+ propertyNames.add(exec->propertyNames().callee);
+ propertyNames.add(exec->propertyNames().length);
+ }
+ JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+void Arguments::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value)
+{
+ Arguments* thisObject = jsCast<Arguments*>(cell);
+ if (i < static_cast<unsigned>(thisObject->d->numArguments) && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
+ thisObject->argument(i).set(exec->globalData(), thisObject, value);
+ return;
+ }
+
+ PutPropertySlot slot;
+ JSObject::put(thisObject, exec, Identifier(exec, UString::number(i)), value, slot);
+}
+
+void Arguments::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ Arguments* thisObject = jsCast<Arguments*>(cell);
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
+ if (isArrayIndex && i < thisObject->d->numArguments && (!thisObject->d->deletedArguments || !thisObject->d->deletedArguments[i])) {
+ thisObject->argument(i).set(exec->globalData(), thisObject, value);
+ return;
+ }
+
+ if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
+ thisObject->d->overrodeLength = true;
+ thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum);
+ return;
+ }
+
+ if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
+ if (!thisObject->d->isStrictMode) {
+ thisObject->d->overrodeCallee = true;
+ thisObject->putDirect(exec->globalData(), propertyName, value, DontEnum);
+ return;
+ }
+ thisObject->createStrictModeCalleeIfNecessary(exec);
+ }
+
+ if (propertyName == exec->propertyNames().caller && thisObject->d->isStrictMode)
+ thisObject->createStrictModeCallerIfNecessary(exec);
+
+ JSObject::put(thisObject, exec, propertyName, value, slot);
+}
+
+bool Arguments::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
+{
+ Arguments* thisObject = jsCast<Arguments*>(cell);
+ if (i < thisObject->d->numArguments) {
+ if (!thisObject->d->deletedArguments) {
+ thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]);
+ memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments);
+ }
+ if (!thisObject->d->deletedArguments[i]) {
+ thisObject->d->deletedArguments[i] = true;
+ return true;
+ }
+ }
+
+ return JSObject::deleteProperty(thisObject, exec, Identifier(exec, UString::number(i)));
+}
+
+bool Arguments::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
+{
+ Arguments* thisObject = jsCast<Arguments*>(cell);
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
+ if (isArrayIndex && i < thisObject->d->numArguments) {
+ if (!thisObject->d->deletedArguments) {
+ thisObject->d->deletedArguments = adoptArrayPtr(new bool[thisObject->d->numArguments]);
+ memset(thisObject->d->deletedArguments.get(), 0, sizeof(bool) * thisObject->d->numArguments);
+ }
+ if (!thisObject->d->deletedArguments[i]) {
+ thisObject->d->deletedArguments[i] = true;
+ return true;
+ }
+ }
+
+ if (propertyName == exec->propertyNames().length && !thisObject->d->overrodeLength) {
+ thisObject->d->overrodeLength = true;
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().callee && !thisObject->d->overrodeCallee) {
+ if (!thisObject->d->isStrictMode) {
+ thisObject->d->overrodeCallee = true;
+ return true;
+ }
+ thisObject->createStrictModeCalleeIfNecessary(exec);
+ }
+
+ if (propertyName == exec->propertyNames().caller && !thisObject->d->isStrictMode)
+ thisObject->createStrictModeCallerIfNecessary(exec);
+
+ return JSObject::deleteProperty(thisObject, exec, propertyName);
+}
+
+void Arguments::tearOff(CallFrame* callFrame)
+{
+ if (isTornOff())
+ return;
+
+ if (!d->numArguments)
+ return;
+
+ d->registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[d->numArguments]);
+ d->registers = d->registerArray.get() + CallFrame::offsetFor(d->numArguments + 1);
+
+ if (!callFrame->isInlineCallFrame()) {
+ for (size_t i = 0; i < d->numArguments; ++i)
+ argument(i).set(callFrame->globalData(), this, callFrame->argument(i));
+ return;
+ }
+
+ InlineCallFrame* inlineCallFrame = callFrame->inlineCallFrame();
+ for (size_t i = 0; i < d->numArguments; ++i) {
+ ValueRecovery& recovery = inlineCallFrame->arguments[i + 1];
+ // In the future we'll support displaced recoveries (indicating that the
+ // argument was flushed to a different location), but for now we don't do
+ // that so this code will fail if that were to happen. On the other hand,
+ // it's much less likely that we'll support in-register recoveries since
+ // this code does not (easily) have access to registers.
+ JSValue value;
+ Register* location = &callFrame->registers()[CallFrame::argumentOffset(i)];
+ switch (recovery.technique()) {
+ case AlreadyInRegisterFile:
+ value = location->jsValue();
+ break;
+ case AlreadyInRegisterFileAsUnboxedInt32:
+ value = jsNumber(location->unboxedInt32());
+ break;
+ case AlreadyInRegisterFileAsUnboxedCell:
+ value = location->unboxedCell();
+ break;
+ case AlreadyInRegisterFileAsUnboxedBoolean:
+ value = jsBoolean(location->unboxedBoolean());
+ break;
+ case AlreadyInRegisterFileAsUnboxedDouble:
+#if USE(JSVALUE64)
+ value = jsNumber(*bitwise_cast<double*>(location));
+#else
+ value = location->jsValue();
+#endif
+ break;
+ case Constant:
+ value = recovery.constant();
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+ argument(i).set(callFrame->globalData(), this, value);
+ }
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Arguments.h b/Source/JavaScriptCore/runtime/Arguments.h
new file mode 100644
index 000000000..3564fe447
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Arguments.h
@@ -0,0 +1,177 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2007 Maks Orlovich
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Arguments_h
+#define Arguments_h
+
+#include "CodeOrigin.h"
+#include "JSActivation.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "Interpreter.h"
+#include "ObjectConstructor.h"
+
+namespace JSC {
+
+ struct ArgumentsData {
+ WTF_MAKE_NONCOPYABLE(ArgumentsData); WTF_MAKE_FAST_ALLOCATED;
+ public:
+ ArgumentsData() { }
+ WriteBarrier<JSActivation> activation;
+
+ unsigned numArguments;
+
+ WriteBarrier<Unknown>* registers;
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray;
+
+ OwnArrayPtr<bool> deletedArguments;
+
+ WriteBarrier<JSFunction> callee;
+ bool overrodeLength : 1;
+ bool overrodeCallee : 1;
+ bool overrodeCaller : 1;
+ bool isStrictMode : 1;
+ };
+
+ class Arguments : public JSNonFinalObject {
+ public:
+ typedef JSNonFinalObject Base;
+
+ static Arguments* create(JSGlobalData& globalData, CallFrame* callFrame)
+ {
+ Arguments* arguments = new (NotNull, allocateCell<Arguments>(globalData.heap)) Arguments(callFrame);
+ arguments->finishCreation(callFrame);
+ return arguments;
+ }
+
+ enum { MaxArguments = 0x10000 };
+
+ private:
+ enum NoParametersType { NoParameters };
+
+ Arguments(CallFrame*);
+ Arguments(CallFrame*, NoParametersType);
+
+ public:
+ static const ClassInfo s_info;
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ void fillArgList(ExecState*, MarkedArgumentBuffer&);
+
+ uint32_t length(ExecState* exec) const
+ {
+ if (UNLIKELY(d->overrodeLength))
+ return get(exec, exec->propertyNames().length).toUInt32(exec);
+ return d->numArguments;
+ }
+
+ void copyToArguments(ExecState*, CallFrame*, uint32_t length);
+ void tearOff(CallFrame*);
+ bool isTornOff() const { return d->registerArray; }
+ void didTearOffActivation(JSGlobalData& globalData, JSActivation* activation)
+ {
+ if (isTornOff())
+ return;
+ d->activation.set(globalData, this, activation);
+ d->registers = &activation->registerAt(0);
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
+
+ void finishCreation(CallFrame*);
+
+ private:
+ static void destroy(JSCell*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+ static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue);
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
+ static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
+ void createStrictModeCallerIfNecessary(ExecState*);
+ void createStrictModeCalleeIfNecessary(ExecState*);
+
+ WriteBarrier<Unknown>& argument(size_t);
+
+ void init(CallFrame*);
+
+ OwnPtr<ArgumentsData> d;
+ };
+
+ Arguments* asArguments(JSValue);
+
+ inline Arguments* asArguments(JSValue value)
+ {
+ ASSERT(asObject(value)->inherits(&Arguments::s_info));
+ return static_cast<Arguments*>(asObject(value));
+ }
+
+ inline Arguments::Arguments(CallFrame* callFrame)
+ : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+ , d(adoptPtr(new ArgumentsData))
+ {
+ }
+
+ inline Arguments::Arguments(CallFrame* callFrame, NoParametersType)
+ : JSNonFinalObject(callFrame->globalData(), callFrame->lexicalGlobalObject()->argumentsStructure())
+ , d(adoptPtr(new ArgumentsData))
+ {
+ }
+
+ inline WriteBarrier<Unknown>& Arguments::argument(size_t i)
+ {
+ return d->registers[CallFrame::argumentOffset(i)];
+ }
+
+ inline void Arguments::finishCreation(CallFrame* callFrame)
+ {
+ Base::finishCreation(callFrame->globalData());
+ ASSERT(inherits(&s_info));
+
+ JSFunction* callee = asFunction(callFrame->callee());
+ d->numArguments = callFrame->argumentCount();
+ d->registers = reinterpret_cast<WriteBarrier<Unknown>*>(callFrame->registers());
+ d->callee.set(callFrame->globalData(), this, callee);
+ d->overrodeLength = false;
+ d->overrodeCallee = false;
+ d->overrodeCaller = false;
+ d->isStrictMode = callFrame->codeBlock()->isStrictMode();
+
+ // The bytecode generator omits op_tear_off_activation in cases of no
+ // declared parameters, so we need to tear off immediately.
+ if (d->isStrictMode || !callee->jsExecutable()->parameterCount())
+ tearOff(callFrame);
+ }
+
+} // namespace JSC
+
+#endif // Arguments_h
diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.cpp b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
new file mode 100644
index 000000000..ebcc43781
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ArrayConstructor.cpp
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008, 2011 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 "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSArray.h"
+#include "JSFunction.h"
+#include "Lookup.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState*);
+
+}
+
+#include "ArrayConstructor.lut.h"
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(ArrayConstructor);
+
+const ClassInfo ArrayConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::arrayConstructorTable, CREATE_METHOD_TABLE(ArrayConstructor) };
+
+/* Source for ArrayConstructor.lut.h
+@begin arrayConstructorTable
+ isArray arrayConstructorIsArray DontEnum|Function 1
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(ArrayConstructor);
+
+ArrayConstructor::ArrayConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void ArrayConstructor::finishCreation(ExecState* exec, ArrayPrototype* arrayPrototype)
+{
+ Base::finishCreation(exec->globalData(), Identifier(exec, arrayPrototype->classInfo()->className));
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, arrayPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+}
+
+bool ArrayConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<InternalFunction>(exec, ExecState::arrayConstructorTable(exec), jsCast<ArrayConstructor*>(cell), propertyName, slot);
+}
+
+bool ArrayConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<InternalFunction>(exec, ExecState::arrayConstructorTable(exec), jsCast<ArrayConstructor*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Functions ---------------------------
+
+static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args)
+{
+ JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
+
+ // a single numeric argument denotes the array size (!)
+ if (args.size() == 1 && args.at(0).isNumber()) {
+ uint32_t n = args.at(0).toUInt32(exec);
+ if (n != args.at(0).toNumber(exec))
+ return throwError(exec, createRangeError(exec, "Array size is not a small enough positive integer."));
+ return constructEmptyArray(exec, globalObject, n);
+ }
+
+ // otherwise the array is constructed with the arguments in it
+ return constructArray(exec, globalObject, args);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWithArrayConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructArrayWithSizeQuirk(exec, args));
+}
+
+ConstructType ArrayConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithArrayConstructor;
+ return ConstructTypeHost;
+}
+
+static EncodedJSValue JSC_HOST_CALL callArrayConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructArrayWithSizeQuirk(exec, args));
+}
+
+CallType ArrayConstructor::getCallData(JSCell*, CallData& callData)
+{
+ // equivalent to 'new Array(....)'
+ callData.native.function = callArrayConstructor;
+ return CallTypeHost;
+}
+
+EncodedJSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState* exec)
+{
+ return JSValue::encode(jsBoolean(exec->argument(0).inherits(&JSArray::s_info)));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayConstructor.h b/Source/JavaScriptCore/runtime/ArrayConstructor.h
new file mode 100644
index 000000000..c60571fbd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ArrayConstructor.h
@@ -0,0 +1,64 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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:
+ typedef InternalFunction Base;
+
+ static ArrayConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ArrayPrototype* arrayPrototype)
+ {
+ ArrayConstructor* constructor = new (NotNull, allocateCell<ArrayConstructor>(*exec->heap())) ArrayConstructor(globalObject, structure);
+ constructor->finishCreation(exec, arrayPrototype);
+ return constructor;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(ExecState*, ArrayPrototype*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+
+ private:
+ ArrayConstructor(JSGlobalObject*, Structure*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ };
+
+} // namespace JSC
+
+#endif // ArrayConstructor_h
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.cpp b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
new file mode 100644
index 000000000..d972693dd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ArrayPrototype.cpp
@@ -0,0 +1,1200 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008, 2009, 2011 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 "CachedCall.h"
+#include "CodeBlock.h"
+#include "Interpreter.h"
+#include "JIT.h"
+#include "JSStringBuilder.h"
+#include "Lookup.h"
+#include "ObjectPrototype.h"
+#include "Operations.h"
+#include "StringRecursionChecker.h"
+#include <algorithm>
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(ArrayPrototype);
+
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState*);
+static EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*);
+
+}
+
+#include "ArrayPrototype.lut.h"
+
+namespace JSC {
+
+static inline bool isNumericCompareFunction(ExecState* exec, CallType callType, const CallData& callData)
+{
+ if (callType != CallTypeJS)
+ return false;
+
+ FunctionExecutable* executable = callData.js.functionExecutable;
+
+ JSObject* error = executable->compileForCall(exec, callData.js.scopeChain);
+ if (error)
+ return false;
+
+ return executable->generatedBytecodeForCall().isNumericCompareFunction();
+}
+
+// ------------------------------ ArrayPrototype ----------------------------
+
+const ClassInfo ArrayPrototype::s_info = {"Array", &JSArray::s_info, 0, ExecState::arrayPrototypeTable, CREATE_METHOD_TABLE(ArrayPrototype)};
+
+/* Source for ArrayPrototype.lut.h
+@begin arrayPrototypeTable 16
+ toString arrayProtoFuncToString DontEnum|Function 0
+ toLocaleString arrayProtoFuncToLocaleString DontEnum|Function 0
+ concat arrayProtoFuncConcat DontEnum|Function 1
+ join arrayProtoFuncJoin DontEnum|Function 1
+ pop arrayProtoFuncPop DontEnum|Function 0
+ push arrayProtoFuncPush DontEnum|Function 1
+ reverse arrayProtoFuncReverse DontEnum|Function 0
+ shift arrayProtoFuncShift DontEnum|Function 0
+ slice arrayProtoFuncSlice DontEnum|Function 2
+ sort arrayProtoFuncSort DontEnum|Function 1
+ splice arrayProtoFuncSplice DontEnum|Function 2
+ unshift arrayProtoFuncUnShift DontEnum|Function 1
+ every arrayProtoFuncEvery DontEnum|Function 1
+ forEach arrayProtoFuncForEach DontEnum|Function 1
+ some arrayProtoFuncSome DontEnum|Function 1
+ indexOf arrayProtoFuncIndexOf DontEnum|Function 1
+ lastIndexOf arrayProtoFuncLastIndexOf DontEnum|Function 1
+ filter arrayProtoFuncFilter DontEnum|Function 1
+ reduce arrayProtoFuncReduce DontEnum|Function 1
+ reduceRight arrayProtoFuncReduceRight DontEnum|Function 1
+ map arrayProtoFuncMap DontEnum|Function 1
+@end
+*/
+
+// ECMA 15.4.4
+ArrayPrototype::ArrayPrototype(JSGlobalObject* globalObject, Structure* structure)
+ : JSArray(globalObject->globalData(), structure)
+{
+}
+
+void ArrayPrototype::finishCreation(JSGlobalObject* globalObject)
+{
+ Base::finishCreation(globalObject->globalData());
+ ASSERT(inherits(&s_info));
+}
+
+bool ArrayPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayPrototypeTable(exec), jsCast<ArrayPrototype*>(cell), propertyName, slot);
+}
+
+bool ArrayPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<JSArray>(exec, ExecState::arrayPrototypeTable(exec), jsCast<ArrayPrototype*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Array Functions ----------------------------
+
+// Helper function
+static JSValue getProperty(ExecState* exec, JSObject* obj, unsigned index)
+{
+ PropertySlot slot(obj);
+ if (!obj->getPropertySlot(exec, index, slot))
+ return JSValue();
+ return slot.getValue(exec, index);
+}
+
+static void putProperty(ExecState* exec, JSObject* obj, const Identifier& propertyName, JSValue value)
+{
+ PutPropertySlot slot;
+ obj->methodTable()->put(obj, exec, propertyName, value, slot);
+}
+
+static unsigned argumentClampedIndexFromStartOrEnd(ExecState* exec, int argument, unsigned length, unsigned undefinedValue = 0)
+{
+ JSValue value = exec->argument(argument);
+ if (value.isUndefined())
+ return undefinedValue;
+
+ double indexDouble = value.toInteger(exec);
+ if (indexDouble < 0) {
+ indexDouble += length;
+ return indexDouble < 0 ? 0 : static_cast<unsigned>(indexDouble);
+ }
+ return indexDouble > length ? length : static_cast<unsigned>(indexDouble);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+
+ bool isRealArray = isJSArray(thisValue);
+ if (!isRealArray && !thisValue.inherits(&JSArray::s_info))
+ return throwVMTypeError(exec);
+ JSArray* thisObj = asArray(thisValue);
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ StringRecursionChecker checker(exec, thisObj);
+ if (JSValue earlyReturnValue = checker.earlyReturnValue())
+ return JSValue::encode(earlyReturnValue);
+
+ unsigned totalSize = length ? length - 1 : 0;
+ Vector<RefPtr<StringImpl>, 256> strBuffer(length);
+ bool allStrings8Bit = true;
+
+ for (unsigned k = 0; k < length; k++) {
+ JSValue element;
+ if (isRealArray && thisObj->canGetIndex(k))
+ element = thisObj->getIndex(k);
+ else
+ element = thisObj->get(exec, k);
+
+ if (element.isUndefinedOrNull())
+ continue;
+
+ UString str = element.toString(exec);
+ strBuffer[k] = str.impl();
+ totalSize += str.length();
+ allStrings8Bit = allStrings8Bit && str.is8Bit();
+
+ if (!strBuffer.data()) {
+ throwOutOfMemoryError(exec);
+ }
+
+ if (exec->hadException())
+ break;
+ }
+ if (!totalSize)
+ return JSValue::encode(jsEmptyString(exec));
+
+ if (allStrings8Bit) {
+ Vector<LChar> buffer;
+ buffer.reserveCapacity(totalSize);
+ if (!buffer.data())
+ return JSValue::encode(throwOutOfMemoryError(exec));
+
+ for (unsigned i = 0; i < length; i++) {
+ if (i)
+ buffer.append(',');
+ if (RefPtr<StringImpl> rep = strBuffer[i])
+ buffer.append(rep->characters8(), rep->length());
+ }
+ ASSERT(buffer.size() == totalSize);
+ return JSValue::encode(jsString(exec, UString::adopt(buffer)));
+ }
+
+ Vector<UChar> buffer;
+ buffer.reserveCapacity(totalSize);
+ if (!buffer.data())
+ return JSValue::encode(throwOutOfMemoryError(exec));
+
+ for (unsigned i = 0; i < length; i++) {
+ if (i)
+ buffer.append(',');
+ if (RefPtr<StringImpl> rep = strBuffer[i])
+ buffer.append(rep->characters(), rep->length());
+ }
+ ASSERT(buffer.size() == totalSize);
+ return JSValue::encode(jsString(exec, UString::adopt(buffer)));
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+
+ if (!thisValue.inherits(&JSArray::s_info))
+ return throwVMTypeError(exec);
+ JSObject* thisObj = asArray(thisValue);
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ StringRecursionChecker checker(exec, thisObj);
+ if (JSValue earlyReturnValue = checker.earlyReturnValue())
+ return JSValue::encode(earlyReturnValue);
+
+ JSStringBuilder strBuffer;
+ for (unsigned k = 0; k < length; k++) {
+ if (k >= 1)
+ strBuffer.append(',');
+
+ JSValue element = thisObj->get(exec, k);
+ if (!element.isUndefinedOrNull()) {
+ JSObject* o = element.toObject(exec);
+ JSValue conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
+ UString str;
+ CallData callData;
+ CallType callType = getCallData(conversionFunction, callData);
+ if (callType != CallTypeNone)
+ str = call(exec, conversionFunction, callType, callData, element, exec->emptyList()).toString(exec);
+ else
+ str = element.toString(exec);
+ strBuffer.append(str);
+ }
+ }
+
+ return JSValue::encode(strBuffer.build(exec));
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncJoin(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ StringRecursionChecker checker(exec, thisObj);
+ if (JSValue earlyReturnValue = checker.earlyReturnValue())
+ return JSValue::encode(earlyReturnValue);
+
+ JSStringBuilder strBuffer;
+
+ UString separator;
+ if (!exec->argument(0).isUndefined())
+ separator = exec->argument(0).toString(exec);
+
+ unsigned k = 0;
+ if (isJSArray(thisObj)) {
+ JSArray* array = asArray(thisObj);
+
+ if (length) {
+ if (!array->canGetIndex(k))
+ goto skipFirstLoop;
+ JSValue element = array->getIndex(k);
+ if (!element.isUndefinedOrNull())
+ strBuffer.append(element.toString(exec));
+ k++;
+ }
+
+ if (separator.isNull()) {
+ for (; k < length; k++) {
+ if (!array->canGetIndex(k))
+ break;
+ strBuffer.append(',');
+ JSValue element = array->getIndex(k);
+ if (!element.isUndefinedOrNull())
+ strBuffer.append(element.toString(exec));
+ }
+ } else {
+ for (; k < length; k++) {
+ if (!array->canGetIndex(k))
+ break;
+ strBuffer.append(separator);
+ JSValue element = array->getIndex(k);
+ if (!element.isUndefinedOrNull())
+ strBuffer.append(element.toString(exec));
+ }
+ }
+ }
+ skipFirstLoop:
+ for (; k < length; k++) {
+ if (k >= 1) {
+ if (separator.isNull())
+ strBuffer.append(',');
+ else
+ strBuffer.append(separator);
+ }
+
+ JSValue element = thisObj->get(exec, k);
+ if (!element.isUndefinedOrNull())
+ strBuffer.append(element.toString(exec));
+ }
+
+ return JSValue::encode(strBuffer.build(exec));
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ JSArray* arr = constructEmptyArray(exec);
+ unsigned n = 0;
+ JSValue curArg = thisValue.toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ size_t i = 0;
+ size_t argCount = exec->argumentCount();
+ while (1) {
+ if (curArg.inherits(&JSArray::s_info)) {
+ unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec);
+ JSObject* curObject = curArg.toObject(exec);
+ for (unsigned k = 0; k < length; ++k) {
+ JSValue v = getProperty(exec, curObject, k);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (v)
+ arr->methodTable()->putByIndex(arr, exec, n, v);
+ n++;
+ }
+ } else {
+ arr->methodTable()->putByIndex(arr, exec, n, curArg);
+ n++;
+ }
+ if (i == argCount)
+ break;
+ curArg = (exec->argument(i));
+ ++i;
+ }
+ arr->setLength(n);
+ return JSValue::encode(arr);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncPop(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+
+ if (isJSArray(thisValue))
+ return JSValue::encode(asArray(thisValue)->pop());
+
+ JSObject* thisObj = thisValue.toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue result;
+ if (length == 0) {
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length));
+ result = jsUndefined();
+ } else {
+ result = thisObj->get(exec, length - 1);
+ thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, length - 1);
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
+ }
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncPush(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+
+ if (isJSArray(thisValue) && exec->argumentCount() == 1) {
+ JSArray* array = asArray(thisValue);
+ array->push(exec, exec->argument(0));
+ return JSValue::encode(jsNumber(array->length()));
+ }
+
+ JSObject* thisObj = thisValue.toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ for (unsigned n = 0; n < exec->argumentCount(); n++) {
+ // Check for integer overflow; where safe we can do a fast put by index.
+ if (length + n >= length)
+ thisObj->methodTable()->putByIndex(thisObj, exec, length + n, exec->argument(n));
+ else {
+ PutPropertySlot slot;
+ Identifier propertyName(exec, JSValue(static_cast<int64_t>(length) + static_cast<int64_t>(n)).toString(exec));
+ thisObj->methodTable()->put(thisObj, exec, propertyName, exec->argument(n), slot);
+ }
+ }
+ JSValue newLength(static_cast<int64_t>(length) + static_cast<int64_t>(exec->argumentCount()));
+ putProperty(exec, thisObj, exec->propertyNames().length, newLength);
+ return JSValue::encode(newLength);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncReverse(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ unsigned middle = length / 2;
+ for (unsigned k = 0; k < middle; k++) {
+ unsigned lk1 = length - k - 1;
+ JSValue obj2 = getProperty(exec, thisObj, lk1);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ JSValue obj = getProperty(exec, thisObj, k);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (obj2)
+ thisObj->methodTable()->putByIndex(thisObj, exec, k, obj2);
+ else
+ thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k);
+
+ if (obj)
+ thisObj->methodTable()->putByIndex(thisObj, exec, lk1, obj);
+ else
+ thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, lk1);
+ }
+ return JSValue::encode(thisObj);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncShift(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue result;
+ if (length == 0) {
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length));
+ result = jsUndefined();
+ } else {
+ result = thisObj->get(exec, 0);
+ if (isJSArray(thisObj))
+ ((JSArray *)thisObj)->shiftCount(exec, 1);
+ else {
+ for (unsigned k = 1; k < length; k++) {
+ JSValue obj = getProperty(exec, thisObj, k);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (obj)
+ thisObj->methodTable()->putByIndex(thisObj, exec, k - 1, obj);
+ else
+ thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k - 1);
+ }
+ thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, length - 1);
+ }
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - 1));
+ }
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSlice(ExecState* exec)
+{
+ // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // We return a new array
+ JSArray* resObj = constructEmptyArray(exec);
+ JSValue result = resObj;
+
+ unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
+ unsigned end = argumentClampedIndexFromStartOrEnd(exec, 1, length, length);
+
+ unsigned n = 0;
+ for (unsigned k = begin; k < end; k++, n++) {
+ JSValue v = getProperty(exec, thisObj, k);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (v)
+ resObj->methodTable()->putByIndex(resObj, exec, n, v);
+ }
+ resObj->setLength(n);
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (!length || exec->hadException())
+ return JSValue::encode(thisObj);
+
+ JSValue function = exec->argument(0);
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+
+ if (thisObj->classInfo() == &JSArray::s_info && !asArray(thisObj)->inSparseMode()) {
+ if (isNumericCompareFunction(exec, callType, callData))
+ asArray(thisObj)->sortNumeric(exec, function, callType, callData);
+ else if (callType != CallTypeNone)
+ asArray(thisObj)->sort(exec, function, callType, callData);
+ else
+ asArray(thisObj)->sort(exec);
+ return JSValue::encode(thisObj);
+ }
+
+ // "Min" sort. Not the fastest, but definitely less code than heapsort
+ // or quicksort, and much less swapping than bubblesort/insertionsort.
+ for (unsigned i = 0; i < length - 1; ++i) {
+ JSValue iObj = thisObj->get(exec, i);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ unsigned themin = i;
+ JSValue minObj = iObj;
+ for (unsigned j = i + 1; j < length; ++j) {
+ JSValue jObj = thisObj->get(exec, j);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ double compareResult;
+ if (jObj.isUndefined())
+ compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
+ else if (minObj.isUndefined())
+ compareResult = -1;
+ else if (callType != CallTypeNone) {
+ MarkedArgumentBuffer l;
+ l.append(jObj);
+ l.append(minObj);
+ compareResult = call(exec, function, callType, callData, jsUndefined(), l).toNumber(exec);
+ } else
+ compareResult = (jObj.toString(exec) < minObj.toString(exec)) ? -1 : 1;
+
+ if (compareResult < 0) {
+ themin = j;
+ minObj = jObj;
+ }
+ }
+ // Swap themin and i
+ if (themin > i) {
+ thisObj->methodTable()->putByIndex(thisObj, exec, i, minObj);
+ thisObj->methodTable()->putByIndex(thisObj, exec, themin, iObj);
+ }
+ }
+ return JSValue::encode(thisObj);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSplice(ExecState* exec)
+{
+ // 15.4.4.12
+
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ if (!exec->argumentCount())
+ return JSValue::encode(constructEmptyArray(exec));
+
+ unsigned begin = argumentClampedIndexFromStartOrEnd(exec, 0, length);
+
+ unsigned deleteCount = length - begin;
+ if (exec->argumentCount() > 1) {
+ double deleteDouble = exec->argument(1).toInteger(exec);
+ if (deleteDouble < 0)
+ deleteCount = 0;
+ else if (deleteDouble > length - begin)
+ deleteCount = length - begin;
+ else
+ deleteCount = static_cast<unsigned>(deleteDouble);
+ }
+
+ JSArray* resObj = JSArray::tryCreateUninitialized(exec->globalData(), exec->lexicalGlobalObject()->arrayStructure(), deleteCount);
+ if (!resObj)
+ return JSValue::encode(throwOutOfMemoryError(exec));
+
+ JSValue result = resObj;
+ JSGlobalData& globalData = exec->globalData();
+ for (unsigned k = 0; k < deleteCount; k++) {
+ JSValue v = getProperty(exec, thisObj, k + begin);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ resObj->initializeIndex(globalData, k, v);
+ }
+ resObj->completeInitialization(deleteCount);
+
+ unsigned additionalArgs = std::max<int>(exec->argumentCount() - 2, 0);
+ if (additionalArgs != deleteCount) {
+ if (additionalArgs < deleteCount) {
+ if ((!begin) && (isJSArray(thisObj)))
+ ((JSArray *)thisObj)->shiftCount(exec, deleteCount - additionalArgs);
+ else {
+ for (unsigned k = begin; k < length - deleteCount; ++k) {
+ JSValue v = getProperty(exec, thisObj, k + deleteCount);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (v)
+ thisObj->methodTable()->putByIndex(thisObj, exec, k + additionalArgs, v);
+ else
+ thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k + additionalArgs);
+ }
+ for (unsigned k = length; k > length - deleteCount + additionalArgs; --k)
+ thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k - 1);
+ }
+ } else {
+ if ((!begin) && (isJSArray(thisObj)))
+ ((JSArray *)thisObj)->unshiftCount(exec, additionalArgs - deleteCount);
+ else {
+ for (unsigned k = length - deleteCount; k > begin; --k) {
+ JSValue obj = getProperty(exec, thisObj, k + deleteCount - 1);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (obj)
+ thisObj->methodTable()->putByIndex(thisObj, exec, k + additionalArgs - 1, obj);
+ else
+ thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k + additionalArgs - 1);
+ }
+ }
+ }
+ }
+ for (unsigned k = 0; k < additionalArgs; ++k)
+ thisObj->methodTable()->putByIndex(thisObj, exec, k + begin, exec->argument(k + 2));
+
+ putProperty(exec, thisObj, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs));
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncUnShift(ExecState* exec)
+{
+ // 15.4.4.13
+
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ unsigned nrArgs = exec->argumentCount();
+ if ((nrArgs) && (length)) {
+ if (isJSArray(thisObj))
+ ((JSArray *)thisObj)->unshiftCount(exec, nrArgs);
+ else {
+ for (unsigned k = length; k > 0; --k) {
+ JSValue v = getProperty(exec, thisObj, k - 1);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (v)
+ thisObj->methodTable()->putByIndex(thisObj, exec, k + nrArgs - 1, v);
+ else
+ thisObj->methodTable()->deletePropertyByIndex(thisObj, exec, k + nrArgs - 1);
+ }
+ }
+ }
+ for (unsigned k = 0; k < nrArgs; ++k)
+ thisObj->methodTable()->putByIndex(thisObj, exec, k, exec->argument(k));
+ JSValue result = jsNumber(length + nrArgs);
+ putProperty(exec, thisObj, exec->propertyNames().length, result);
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncFilter(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue function = exec->argument(0);
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+
+ JSValue applyThis = exec->argument(1);
+ JSArray* resultArray = constructEmptyArray(exec);
+
+ unsigned filterIndex = 0;
+ unsigned k = 0;
+ if (callType == CallTypeJS && isJSArray(thisObj)) {
+ JSFunction* f = asFunction(function);
+ JSArray* array = asArray(thisObj);
+ CachedCall cachedCall(exec, f, 3);
+ for (; k < length && !exec->hadException(); ++k) {
+ if (!array->canGetIndex(k))
+ break;
+ JSValue v = array->getIndex(k);
+ cachedCall.setThis(applyThis);
+ cachedCall.setArgument(0, v);
+ cachedCall.setArgument(1, jsNumber(k));
+ cachedCall.setArgument(2, thisObj);
+
+ JSValue result = cachedCall.call();
+ if (result.toBoolean(exec))
+ resultArray->methodTable()->putByIndex(resultArray, exec, filterIndex++, v);
+ }
+ if (k == length)
+ return JSValue::encode(resultArray);
+ }
+ for (; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot(thisObj);
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+ JSValue v = slot.getValue(exec, k);
+
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ MarkedArgumentBuffer eachArguments;
+ eachArguments.append(v);
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ JSValue result = call(exec, function, callType, callData, applyThis, eachArguments);
+ if (result.toBoolean(exec))
+ resultArray->methodTable()->putByIndex(resultArray, exec, filterIndex++, v);
+ }
+ return JSValue::encode(resultArray);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncMap(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue function = exec->argument(0);
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+
+ JSValue applyThis = exec->argument(1);
+
+ JSArray* resultArray = constructEmptyArray(exec, length);
+ unsigned k = 0;
+ if (callType == CallTypeJS && isJSArray(thisObj)) {
+ JSFunction* f = asFunction(function);
+ JSArray* array = asArray(thisObj);
+ CachedCall cachedCall(exec, f, 3);
+ for (; k < length && !exec->hadException(); ++k) {
+ if (UNLIKELY(!array->canGetIndex(k)))
+ break;
+
+ cachedCall.setThis(applyThis);
+ cachedCall.setArgument(0, array->getIndex(k));
+ cachedCall.setArgument(1, jsNumber(k));
+ cachedCall.setArgument(2, thisObj);
+
+ JSArray::putByIndex(resultArray, exec, k, cachedCall.call());
+ }
+ }
+ for (; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot(thisObj);
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+ JSValue v = slot.getValue(exec, k);
+
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ MarkedArgumentBuffer eachArguments;
+ eachArguments.append(v);
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue result = call(exec, function, callType, callData, applyThis, eachArguments);
+ resultArray->methodTable()->putByIndex(resultArray, exec, k, result);
+ }
+
+ return JSValue::encode(resultArray);
+}
+
+// Documentation for these three is available at:
+// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every
+// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
+// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue function = exec->argument(0);
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+
+ JSValue applyThis = exec->argument(1);
+
+ JSValue result = jsBoolean(true);
+
+ unsigned k = 0;
+ if (callType == CallTypeJS && isJSArray(thisObj)) {
+ JSFunction* f = asFunction(function);
+ JSArray* array = asArray(thisObj);
+ CachedCall cachedCall(exec, f, 3);
+ for (; k < length && !exec->hadException(); ++k) {
+ if (UNLIKELY(!array->canGetIndex(k)))
+ break;
+
+ cachedCall.setThis(applyThis);
+ cachedCall.setArgument(0, array->getIndex(k));
+ cachedCall.setArgument(1, jsNumber(k));
+ cachedCall.setArgument(2, thisObj);
+ JSValue result = cachedCall.call();
+ if (!result.toBoolean(cachedCall.newCallFrame(exec)))
+ return JSValue::encode(jsBoolean(false));
+ }
+ }
+ for (; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot(thisObj);
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+
+ MarkedArgumentBuffer eachArguments;
+ eachArguments.append(slot.getValue(exec, k));
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
+ if (!predicateResult) {
+ result = jsBoolean(false);
+ break;
+ }
+ }
+
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncForEach(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue function = exec->argument(0);
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+
+ JSValue applyThis = exec->argument(1);
+
+ unsigned k = 0;
+ if (callType == CallTypeJS && isJSArray(thisObj)) {
+ JSFunction* f = asFunction(function);
+ JSArray* array = asArray(thisObj);
+ CachedCall cachedCall(exec, f, 3);
+ for (; k < length && !exec->hadException(); ++k) {
+ if (UNLIKELY(!array->canGetIndex(k)))
+ break;
+
+ cachedCall.setThis(applyThis);
+ cachedCall.setArgument(0, array->getIndex(k));
+ cachedCall.setArgument(1, jsNumber(k));
+ cachedCall.setArgument(2, thisObj);
+
+ cachedCall.call();
+ }
+ }
+ for (; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot(thisObj);
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+
+ MarkedArgumentBuffer eachArguments;
+ eachArguments.append(slot.getValue(exec, k));
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ call(exec, function, callType, callData, applyThis, eachArguments);
+ }
+ return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue function = exec->argument(0);
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+
+ JSValue applyThis = exec->argument(1);
+
+ JSValue result = jsBoolean(false);
+
+ unsigned k = 0;
+ if (callType == CallTypeJS && isJSArray(thisObj)) {
+ JSFunction* f = asFunction(function);
+ JSArray* array = asArray(thisObj);
+ CachedCall cachedCall(exec, f, 3);
+ for (; k < length && !exec->hadException(); ++k) {
+ if (UNLIKELY(!array->canGetIndex(k)))
+ break;
+
+ cachedCall.setThis(applyThis);
+ cachedCall.setArgument(0, array->getIndex(k));
+ cachedCall.setArgument(1, jsNumber(k));
+ cachedCall.setArgument(2, thisObj);
+ JSValue result = cachedCall.call();
+ if (result.toBoolean(cachedCall.newCallFrame(exec)))
+ return JSValue::encode(jsBoolean(true));
+ }
+ }
+ for (; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot(thisObj);
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+
+ MarkedArgumentBuffer eachArguments;
+ eachArguments.append(slot.getValue(exec, k));
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ bool predicateResult = call(exec, function, callType, callData, applyThis, eachArguments).toBoolean(exec);
+ if (predicateResult) {
+ result = jsBoolean(true);
+ break;
+ }
+ }
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduce(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue function = exec->argument(0);
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+
+ unsigned i = 0;
+ JSValue rv;
+ if (!length && exec->argumentCount() == 1)
+ return throwVMTypeError(exec);
+
+ JSArray* array = 0;
+ if (isJSArray(thisObj))
+ array = asArray(thisObj);
+
+ if (exec->argumentCount() >= 2)
+ rv = exec->argument(1);
+ else if (array && array->canGetIndex(0)){
+ rv = array->getIndex(0);
+ i = 1;
+ } else {
+ for (i = 0; i < length; i++) {
+ rv = getProperty(exec, thisObj, i);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (rv)
+ break;
+ }
+ if (!rv)
+ return throwVMTypeError(exec);
+ i++;
+ }
+
+ if (callType == CallTypeJS && array) {
+ CachedCall cachedCall(exec, asFunction(function), 4);
+ for (; i < length && !exec->hadException(); ++i) {
+ cachedCall.setThis(jsUndefined());
+ cachedCall.setArgument(0, rv);
+ JSValue v;
+ if (LIKELY(array->canGetIndex(i)))
+ v = array->getIndex(i);
+ else
+ break; // length has been made unsafe while we enumerate fallback to slow path
+ cachedCall.setArgument(1, v);
+ cachedCall.setArgument(2, jsNumber(i));
+ cachedCall.setArgument(3, array);
+ rv = cachedCall.call();
+ }
+ if (i == length) // only return if we reached the end of the array
+ return JSValue::encode(rv);
+ }
+
+ for (; i < length && !exec->hadException(); ++i) {
+ JSValue prop = getProperty(exec, thisObj, i);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (!prop)
+ continue;
+
+ MarkedArgumentBuffer eachArguments;
+ eachArguments.append(rv);
+ eachArguments.append(prop);
+ eachArguments.append(jsNumber(i));
+ eachArguments.append(thisObj);
+
+ rv = call(exec, function, callType, callData, jsUndefined(), eachArguments);
+ }
+ return JSValue::encode(rv);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncReduceRight(ExecState* exec)
+{
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSValue function = exec->argument(0);
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+
+ unsigned i = 0;
+ JSValue rv;
+ if (!length && exec->argumentCount() == 1)
+ return throwVMTypeError(exec);
+
+ JSArray* array = 0;
+ if (isJSArray(thisObj))
+ array = asArray(thisObj);
+
+ if (exec->argumentCount() >= 2)
+ rv = exec->argument(1);
+ else if (array && array->canGetIndex(length - 1)){
+ rv = array->getIndex(length - 1);
+ i = 1;
+ } else {
+ for (i = 0; i < length; i++) {
+ rv = getProperty(exec, thisObj, length - i - 1);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (rv)
+ break;
+ }
+ if (!rv)
+ return throwVMTypeError(exec);
+ i++;
+ }
+
+ if (callType == CallTypeJS && array) {
+ CachedCall cachedCall(exec, asFunction(function), 4);
+ for (; i < length && !exec->hadException(); ++i) {
+ unsigned idx = length - i - 1;
+ cachedCall.setThis(jsUndefined());
+ cachedCall.setArgument(0, rv);
+ if (UNLIKELY(!array->canGetIndex(idx)))
+ break; // length has been made unsafe while we enumerate fallback to slow path
+ cachedCall.setArgument(1, array->getIndex(idx));
+ cachedCall.setArgument(2, jsNumber(idx));
+ cachedCall.setArgument(3, array);
+ rv = cachedCall.call();
+ }
+ if (i == length) // only return if we reached the end of the array
+ return JSValue::encode(rv);
+ }
+
+ for (; i < length && !exec->hadException(); ++i) {
+ unsigned idx = length - i - 1;
+ JSValue prop = getProperty(exec, thisObj, idx);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (!prop)
+ continue;
+
+ MarkedArgumentBuffer eachArguments;
+ eachArguments.append(rv);
+ eachArguments.append(prop);
+ eachArguments.append(jsNumber(idx));
+ eachArguments.append(thisObj);
+
+ rv = call(exec, function, callType, callData, jsUndefined(), eachArguments);
+ }
+ return JSValue::encode(rv);
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec)
+{
+ // 15.4.4.14
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ unsigned index = argumentClampedIndexFromStartOrEnd(exec, 1, length);
+ JSValue searchElement = exec->argument(0);
+ for (; index < length; ++index) {
+ JSValue e = getProperty(exec, thisObj, index);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (!e)
+ continue;
+ if (JSValue::strictEqual(exec, searchElement, e))
+ return JSValue::encode(jsNumber(index));
+ }
+
+ return JSValue::encode(jsNumber(-1));
+}
+
+EncodedJSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec)
+{
+ // 15.4.4.15
+ JSObject* thisObj = exec->hostThisValue().toObject(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (!length)
+ return JSValue::encode(jsNumber(-1));
+
+ unsigned index = length - 1;
+ if (exec->argumentCount() >= 2) {
+ JSValue fromValue = exec->argument(1);
+ double fromDouble = fromValue.toInteger(exec);
+ if (fromDouble < 0) {
+ fromDouble += length;
+ if (fromDouble < 0)
+ return JSValue::encode(jsNumber(-1));
+ }
+ if (fromDouble < length)
+ index = static_cast<unsigned>(fromDouble);
+ }
+
+ JSValue searchElement = exec->argument(0);
+ do {
+ ASSERT(index < length);
+ JSValue e = getProperty(exec, thisObj, index);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (!e)
+ continue;
+ if (JSValue::strictEqual(exec, searchElement, e))
+ return JSValue::encode(jsNumber(index));
+ } while (index--);
+
+ return JSValue::encode(jsNumber(-1));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ArrayPrototype.h b/Source/JavaScriptCore/runtime/ArrayPrototype.h
new file mode 100644
index 000000000..f49a9a667
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ArrayPrototype.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2007, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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 {
+ private:
+ ArrayPrototype(JSGlobalObject*, Structure*);
+
+ public:
+ typedef JSArray Base;
+
+ static ArrayPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ ArrayPrototype* prototype = new (NotNull, allocateCell<ArrayPrototype>(*exec->heap())) ArrayPrototype(globalObject, structure);
+ prototype->finishCreation(globalObject);
+ return prototype;
+ }
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(JSGlobalObject*);
+ };
+
+} // namespace JSC
+
+#endif // ArrayPrototype_h
diff --git a/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
new file mode 100644
index 000000000..610b8d16c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BatchedTransitionOptimizer.h
@@ -0,0 +1,56 @@
+// -*- 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 "JSObject.h"
+
+namespace JSC {
+
+ class BatchedTransitionOptimizer {
+ WTF_MAKE_NONCOPYABLE(BatchedTransitionOptimizer);
+ public:
+ BatchedTransitionOptimizer(JSGlobalData& globalData, JSObject* object)
+ : m_globalData(&globalData)
+ , m_object(object)
+ {
+ }
+
+ ~BatchedTransitionOptimizer()
+ {
+ if (m_object->structure()->isDictionary())
+ m_object->flattenDictionaryObject(*m_globalData);
+ }
+
+ private:
+ JSGlobalData* m_globalData;
+ JSObject* m_object;
+ };
+
+} // namespace JSC
+
+#endif // BatchedTransitionOptimizer_h
diff --git a/Source/JavaScriptCore/runtime/BigInteger.h b/Source/JavaScriptCore/runtime/BigInteger.h
new file mode 100644
index 000000000..833829df6
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BigInteger.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef BigInteger_h
+#define BigInteger_h
+
+#include <wtf/MathExtras.h>
+
+namespace JSC {
+
+// This is used in converting the integer part of a number to a string.
+class BigInteger {
+public:
+ BigInteger(double number)
+ {
+ ASSERT(isfinite(number) && !signbit(number));
+ ASSERT(number == floor(number));
+
+ bool sign;
+ int32_t exponent;
+ uint64_t mantissa;
+ decomposeDouble(number, sign, exponent, mantissa);
+ ASSERT(!sign && exponent >= 0);
+
+ int32_t zeroBits = exponent - 52;
+
+ if (zeroBits < 0) {
+ mantissa >>= -zeroBits;
+ zeroBits = 0;
+ }
+
+ while (zeroBits >= 32) {
+ m_values.append(0);
+ zeroBits -= 32;
+ }
+
+ // Left align the 53 bits of the mantissa within 96 bits.
+ uint32_t values[3];
+ values[0] = static_cast<uint32_t>(mantissa);
+ values[1] = static_cast<uint32_t>(mantissa >> 32);
+ values[2] = 0;
+ // Shift based on the remainder of the exponent.
+ if (zeroBits) {
+ values[2] = values[1] >> (32 - zeroBits);
+ values[1] = (values[1] << zeroBits) | (values[0] >> (32 - zeroBits));
+ values[0] = (values[0] << zeroBits);
+ }
+ m_values.append(values[0]);
+ m_values.append(values[1]);
+ m_values.append(values[2]);
+
+ // Canonicalize; remove all trailing zeros.
+ while (m_values.size() && !m_values.last())
+ m_values.removeLast();
+ }
+
+ uint32_t divide(uint32_t divisor)
+ {
+ uint32_t carry = 0;
+
+ for (size_t i = m_values.size(); i; ) {
+ --i;
+ uint64_t dividend = (static_cast<uint64_t>(carry) << 32) + static_cast<uint64_t>(m_values[i]);
+
+ uint64_t result = dividend / static_cast<uint64_t>(divisor);
+ ASSERT(result == static_cast<uint32_t>(result));
+ uint64_t remainder = dividend % static_cast<uint64_t>(divisor);
+ ASSERT(remainder == static_cast<uint32_t>(remainder));
+
+ m_values[i] = static_cast<uint32_t>(result);
+ carry = static_cast<uint32_t>(remainder);
+ }
+
+ // Canonicalize; remove all trailing zeros.
+ while (m_values.size() && !m_values.last())
+ m_values.removeLast();
+
+ return carry;
+ }
+
+ bool operator!() { return !m_values.size(); }
+
+private:
+ Vector<uint32_t, 36> m_values;
+};
+
+}
+
+#endif
+
diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.cpp b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp
new file mode 100644
index 000000000..a54d281a7
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BooleanConstructor.cpp
@@ -0,0 +1,87 @@
+/*
+ * 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);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanConstructor);
+
+const ClassInfo BooleanConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanConstructor) };
+
+BooleanConstructor::BooleanConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void BooleanConstructor::finishCreation(ExecState* exec, BooleanPrototype* booleanPrototype)
+{
+ Base::finishCreation(exec->globalData(), Identifier(exec, booleanPrototype->classInfo()->className));
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly);
+
+ // no. of arguments for constructor
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
+}
+
+// ECMA 15.6.2
+JSObject* constructBoolean(ExecState* exec, const ArgList& args)
+{
+ BooleanObject* obj = BooleanObject::create(exec->globalData(), asInternalFunction(exec->callee())->globalObject()->booleanObjectStructure());
+ obj->setInternalValue(exec->globalData(), jsBoolean(args.at(0).toBoolean(exec)));
+ return obj;
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWithBooleanConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructBoolean(exec, args));
+}
+
+ConstructType BooleanConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithBooleanConstructor;
+ return ConstructTypeHost;
+}
+
+// ECMA 15.6.1
+static EncodedJSValue JSC_HOST_CALL callBooleanConstructor(ExecState* exec)
+{
+ return JSValue::encode(jsBoolean(exec->argument(0).toBoolean(exec)));
+}
+
+CallType BooleanConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callBooleanConstructor;
+ return CallTypeHost;
+}
+
+JSObject* constructBooleanFromImmediateBoolean(ExecState* exec, JSGlobalObject* globalObject, JSValue immediateBooleanValue)
+{
+ BooleanObject* obj = BooleanObject::create(exec->globalData(), globalObject->booleanObjectStructure());
+ obj->setInternalValue(exec->globalData(), immediateBooleanValue);
+ return obj;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanConstructor.h b/Source/JavaScriptCore/runtime/BooleanConstructor.h
new file mode 100644
index 000000000..2b6bafa2f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BooleanConstructor.h
@@ -0,0 +1,62 @@
+/*
+ * 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:
+ typedef InternalFunction Base;
+
+ static BooleanConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, BooleanPrototype* booleanPrototype)
+ {
+ BooleanConstructor* constructor = new (NotNull, allocateCell<BooleanConstructor>(*exec->heap())) BooleanConstructor(globalObject, structure);
+ constructor->finishCreation(exec, booleanPrototype);
+ return constructor;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(ExecState*, BooleanPrototype*);
+
+ private:
+ BooleanConstructor(JSGlobalObject*, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ };
+
+ JSObject* constructBooleanFromImmediateBoolean(ExecState*, JSGlobalObject*, JSValue);
+ JSObject* constructBoolean(ExecState*, const ArgList&);
+
+} // namespace JSC
+
+#endif // BooleanConstructor_h
diff --git a/Source/JavaScriptCore/runtime/BooleanObject.cpp b/Source/JavaScriptCore/runtime/BooleanObject.cpp
new file mode 100644
index 000000000..37c6eab0d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BooleanObject.cpp
@@ -0,0 +1,42 @@
+/*
+ * 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);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanObject);
+
+const ClassInfo BooleanObject::s_info = { "Boolean", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(BooleanObject) };
+
+BooleanObject::BooleanObject(JSGlobalData& globalData, Structure* structure)
+ : JSWrapperObject(globalData, structure)
+{
+}
+
+void BooleanObject::finishCreation(JSGlobalData& globalData)
+{
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanObject.h b/Source/JavaScriptCore/runtime/BooleanObject.h
new file mode 100644
index 000000000..2704ff3cd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BooleanObject.h
@@ -0,0 +1,61 @@
+/*
+ * 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 {
+ protected:
+ BooleanObject(JSGlobalData&, Structure*);
+ void finishCreation(JSGlobalData&);
+
+ public:
+ typedef JSWrapperObject Base;
+
+ static BooleanObject* create(JSGlobalData& globalData, Structure* structure)
+ {
+ BooleanObject* boolean = new (NotNull, allocateCell<BooleanObject>(globalData.heap)) BooleanObject(globalData, structure);
+ boolean->finishCreation(globalData);
+ return boolean;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+ };
+
+ BooleanObject* asBooleanObject(JSValue);
+
+ inline BooleanObject* asBooleanObject(JSValue value)
+ {
+ ASSERT(asObject(value)->inherits(&BooleanObject::s_info));
+ return static_cast<BooleanObject*>(asObject(value));
+ }
+
+} // namespace JSC
+
+#endif // BooleanObject_h
diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.cpp b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
new file mode 100644
index 000000000..b9605d0cf
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BooleanPrototype.cpp
@@ -0,0 +1,109 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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 "ExceptionHelpers.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "ObjectPrototype.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState*);
+
+}
+
+#include "BooleanPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo BooleanPrototype::s_info = { "Boolean", &BooleanObject::s_info, 0, ExecState::booleanPrototypeTable, CREATE_METHOD_TABLE(BooleanPrototype) };
+
+/* Source for BooleanPrototype.lut.h
+@begin booleanPrototypeTable
+ toString booleanProtoFuncToString DontEnum|Function 0
+ valueOf booleanProtoFuncValueOf DontEnum|Function 0
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(BooleanPrototype);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(BooleanPrototype);
+
+BooleanPrototype::BooleanPrototype(ExecState* exec, Structure* structure)
+ : BooleanObject(exec->globalData(), structure)
+{
+}
+
+void BooleanPrototype::finishCreation(ExecState* exec, JSGlobalObject*)
+{
+ Base::finishCreation(exec->globalData());
+ setInternalValue(exec->globalData(), jsBoolean(false));
+
+ ASSERT(inherits(&s_info));
+}
+
+bool BooleanPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<BooleanObject>(exec, ExecState::booleanPrototypeTable(exec), jsCast<BooleanPrototype*>(cell), propertyName, slot);
+}
+
+bool BooleanPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<BooleanObject>(exec, ExecState::booleanPrototypeTable(exec), jsCast<BooleanPrototype*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Functions ---------------------------
+
+EncodedJSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue == jsBoolean(false))
+ return JSValue::encode(jsNontrivialString(exec, "false"));
+
+ if (thisValue == jsBoolean(true))
+ return JSValue::encode(jsNontrivialString(exec, "true"));
+
+ if (!thisValue.inherits(&BooleanObject::s_info))
+ return throwVMTypeError(exec);
+
+ if (asBooleanObject(thisValue)->internalValue() == jsBoolean(false))
+ return JSValue::encode(jsNontrivialString(exec, "false"));
+
+ ASSERT(asBooleanObject(thisValue)->internalValue() == jsBoolean(true));
+ return JSValue::encode(jsNontrivialString(exec, "true"));
+}
+
+EncodedJSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isBoolean())
+ return JSValue::encode(thisValue);
+
+ if (!thisValue.inherits(&BooleanObject::s_info))
+ return throwVMTypeError(exec);
+
+ return JSValue::encode(asBooleanObject(thisValue)->internalValue());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/BooleanPrototype.h b/Source/JavaScriptCore/runtime/BooleanPrototype.h
new file mode 100644
index 000000000..f35d586e6
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/BooleanPrototype.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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:
+ typedef BooleanObject Base;
+
+ static BooleanPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ BooleanPrototype* prototype = new (NotNull, allocateCell<BooleanPrototype>(*exec->heap())) BooleanPrototype(exec, structure);
+ prototype->finishCreation(exec, globalObject);
+ return prototype;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(ExecState*, JSGlobalObject*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | BooleanObject::StructureFlags;
+
+ private:
+ BooleanPrototype(ExecState*, Structure*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ };
+
+} // namespace JSC
+
+#endif // BooleanPrototype_h
diff --git a/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h b/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h
new file mode 100644
index 000000000..f31b4a07f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/CachedTranscendentalFunction.h
@@ -0,0 +1,101 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED 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 CachedTranscendentalFunction_h
+#define CachedTranscendentalFunction_h
+
+#include "JSValue.h"
+
+namespace JSC {
+
+typedef double (*TranscendentalFunctionPtr)(double);
+
+// CachedTranscendentalFunction provides a generic mechanism to cache results
+// for pure functions with the signature "double func(double)", and where NaN
+// maps to NaN.
+template<TranscendentalFunctionPtr orignalFunction>
+class CachedTranscendentalFunction {
+ struct CacheEntry {
+ double operand;
+ double result;
+ };
+
+public:
+ CachedTranscendentalFunction()
+ : m_cache(0)
+ {
+ }
+
+ ~CachedTranscendentalFunction()
+ {
+ if (m_cache)
+ fastFree(m_cache);
+ }
+
+ JSValue operator() (double operand)
+ {
+ if (UNLIKELY(!m_cache))
+ initialize();
+ CacheEntry* entry = &m_cache[hash(operand)];
+
+ if (entry->operand == operand)
+ return jsDoubleNumber(entry->result);
+ double result = orignalFunction(operand);
+ entry->operand = operand;
+ entry->result = result;
+ return jsDoubleNumber(result);
+ }
+
+private:
+ void initialize()
+ {
+ // Lazily allocate the table, populate with NaN->NaN mapping.
+ m_cache = static_cast<CacheEntry*>(fastMalloc(s_cacheSize * sizeof(CacheEntry)));
+ for (unsigned x = 0; x < s_cacheSize; ++x) {
+ m_cache[x].operand = std::numeric_limits<double>::quiet_NaN();
+ m_cache[x].result = std::numeric_limits<double>::quiet_NaN();
+ }
+ }
+
+ static unsigned hash(double d)
+ {
+ union doubleAndUInt64 {
+ double d;
+ uint32_t is[2];
+ } u;
+ u.d = d;
+
+ unsigned x = u.is[0] ^ u.is[1];
+ x = (x >> 20) ^ (x >> 8);
+ return x & (s_cacheSize - 1);
+ }
+
+ static const unsigned s_cacheSize = 0x1000;
+ CacheEntry* m_cache;
+};
+
+}
+
+#endif // CachedTranscendentalFunction_h
diff --git a/Source/JavaScriptCore/runtime/CallData.cpp b/Source/JavaScriptCore/runtime/CallData.cpp
new file mode 100644
index 000000000..ff71fa0cb
--- /dev/null
+++ b/Source/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 "Executable.h"
+#include "Interpreter.h"
+#include "JSFunction.h"
+
+namespace JSC {
+
+JSValue call(ExecState* exec, JSValue functionObject, CallType callType, const CallData& callData, JSValue thisValue, const ArgList& args)
+{
+ ASSERT(callType == CallTypeJS || callType == CallTypeHost);
+ ASSERT(isValidThisObject(thisValue, exec));
+ return exec->interpreter()->executeCall(exec, asObject(functionObject), callType, callData, thisValue, args);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CallData.h b/Source/JavaScriptCore/runtime/CallData.h
new file mode 100644
index 000000000..b138f5484
--- /dev/null
+++ b/Source/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 "JSValue.h"
+
+namespace JSC {
+
+ class ArgList;
+ class ExecState;
+ class FunctionExecutable;
+ class JSObject;
+ class ScopeChainNode;
+
+ enum CallType {
+ CallTypeNone,
+ CallTypeHost,
+ CallTypeJS
+ };
+
+ typedef EncodedJSValue (JSC_HOST_CALL *NativeFunction)(ExecState*);
+
+ union CallData {
+ struct {
+ NativeFunction function;
+ } native;
+ struct {
+ FunctionExecutable* functionExecutable;
+ ScopeChainNode* scopeChain;
+ } js;
+ };
+
+ JSValue call(ExecState*, JSValue functionObject, CallType, const CallData&, JSValue thisValue, const ArgList&);
+
+} // namespace JSC
+
+#endif // CallData_h
diff --git a/Source/JavaScriptCore/runtime/ClassInfo.h b/Source/JavaScriptCore/runtime/ClassInfo.h
new file mode 100644
index 000000000..9fff64e67
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ClassInfo.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ClassInfo_h
+#define ClassInfo_h
+
+#include "CallFrame.h"
+#include "ConstructData.h"
+#include "JSCell.h"
+
+namespace JSC {
+
+ class HashEntry;
+ struct HashTable;
+
+ struct MethodTable {
+ typedef void (*DestroyFunctionPtr)(JSCell*);
+ DestroyFunctionPtr destroy;
+
+ typedef void (*VisitChildrenFunctionPtr)(JSCell*, SlotVisitor&);
+ VisitChildrenFunctionPtr visitChildren;
+
+ typedef CallType (*GetCallDataFunctionPtr)(JSCell*, CallData&);
+ GetCallDataFunctionPtr getCallData;
+
+ typedef ConstructType (*GetConstructDataFunctionPtr)(JSCell*, ConstructData&);
+ GetConstructDataFunctionPtr getConstructData;
+
+ typedef void (*PutFunctionPtr)(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+ PutFunctionPtr put;
+
+ typedef void (*PutByIndexFunctionPtr)(JSCell*, ExecState*, unsigned propertyName, JSValue);
+ PutByIndexFunctionPtr putByIndex;
+
+ typedef bool (*DeletePropertyFunctionPtr)(JSCell*, ExecState*, const Identifier&);
+ DeletePropertyFunctionPtr deleteProperty;
+
+ typedef bool (*DeletePropertyByIndexFunctionPtr)(JSCell*, ExecState*, unsigned);
+ DeletePropertyByIndexFunctionPtr deletePropertyByIndex;
+
+ typedef bool (*GetOwnPropertySlotFunctionPtr)(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ GetOwnPropertySlotFunctionPtr getOwnPropertySlot;
+
+ typedef bool (*GetOwnPropertySlotByIndexFunctionPtr)(JSCell*, ExecState*, unsigned, PropertySlot&);
+ GetOwnPropertySlotByIndexFunctionPtr getOwnPropertySlotByIndex;
+
+ typedef JSObject* (*ToThisObjectFunctionPtr)(JSCell*, ExecState*);
+ ToThisObjectFunctionPtr toThisObject;
+
+ typedef void (*DefineGetterFunctionPtr)(JSObject*, ExecState*, const Identifier&, JSObject*, unsigned);
+ DefineGetterFunctionPtr defineGetter;
+
+ typedef void (*DefineSetterFunctionPtr)(JSObject*, ExecState*, const Identifier&, JSObject*, unsigned);
+ DefineSetterFunctionPtr defineSetter;
+
+ typedef JSValue (*DefaultValueFunctionPtr)(const JSObject*, ExecState*, PreferredPrimitiveType);
+ DefaultValueFunctionPtr defaultValue;
+
+ typedef void (*GetOwnPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ GetOwnPropertyNamesFunctionPtr getOwnPropertyNames;
+
+ typedef void (*GetPropertyNamesFunctionPtr)(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ GetPropertyNamesFunctionPtr getPropertyNames;
+
+ typedef UString (*ClassNameFunctionPtr)(const JSObject*);
+ ClassNameFunctionPtr className;
+
+ typedef bool (*HasInstanceFunctionPtr)(JSObject*, ExecState*, JSValue, JSValue);
+ HasInstanceFunctionPtr hasInstance;
+
+ typedef void (*PutWithAttributesFunctionPtr)(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes);
+ PutWithAttributesFunctionPtr putWithAttributes;
+
+ typedef bool (*DefineOwnPropertyFunctionPtr)(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&, bool);
+ DefineOwnPropertyFunctionPtr defineOwnProperty;
+
+ typedef bool (*GetOwnPropertyDescriptorFunctionPtr)(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ GetOwnPropertyDescriptorFunctionPtr getOwnPropertyDescriptor;
+ };
+
+#define CREATE_MEMBER_CHECKER(member) \
+template <typename T> \
+struct MemberCheck##member { \
+ struct Fallback { \
+ void member(...); \
+ }; \
+ struct Derived : T, Fallback { }; \
+ template <typename U, U> struct Check; \
+ typedef char Yes[2]; \
+ typedef char No[1]; \
+ template <typename U> \
+ static No &func(Check<void (Fallback::*)(...), &U::member>*); \
+ template <typename U> \
+ static Yes &func(...); \
+ enum { has = sizeof(func<Derived>(0)) == sizeof(Yes) }; \
+}
+
+#define HAS_MEMBER_NAMED(klass, name) (MemberCheck##name<klass>::has)
+
+#define CREATE_METHOD_TABLE(ClassName) { \
+ &ClassName::destroy, \
+ &ClassName::visitChildren, \
+ &ClassName::getCallData, \
+ &ClassName::getConstructData, \
+ &ClassName::put, \
+ &ClassName::putByIndex, \
+ &ClassName::deleteProperty, \
+ &ClassName::deletePropertyByIndex, \
+ &ClassName::getOwnPropertySlot, \
+ &ClassName::getOwnPropertySlotByIndex, \
+ &ClassName::toThisObject, \
+ &ClassName::defineGetter, \
+ &ClassName::defineSetter, \
+ &ClassName::defaultValue, \
+ &ClassName::getOwnPropertyNames, \
+ &ClassName::getPropertyNames, \
+ &ClassName::className, \
+ &ClassName::hasInstance, \
+ &ClassName::putWithAttributes, \
+ &ClassName::defineOwnProperty, \
+ &ClassName::getOwnPropertyDescriptor, \
+ }, \
+ sizeof(ClassName), \
+ ClassName::TypedArrayStorageType
+
+ 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;
+ }
+
+ bool isSubClassOf(const ClassInfo* other) const
+ {
+ for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
+ if (ci == other)
+ return true;
+ }
+ return false;
+ }
+
+ bool hasStaticProperties() const
+ {
+ for (const ClassInfo* ci = this; ci; ci = ci->parentClass) {
+ if (ci->staticPropHashTable || ci->classPropHashTableGetterFunction)
+ return true;
+ }
+ return false;
+ }
+
+ const HashTable* staticPropHashTable;
+ typedef const HashTable* (*ClassPropHashTableGetterFunction)(ExecState*);
+ const ClassPropHashTableGetterFunction classPropHashTableGetterFunction;
+
+ MethodTable methodTable;
+
+ size_t cellSize;
+
+ TypedArrayType typedArrayStorageType;
+ };
+
+} // namespace JSC
+
+#endif // ClassInfo_h
diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
new file mode 100644
index 000000000..82beda336
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.cpp
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2003, 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "CommonIdentifiers.h"
+
+namespace JSC {
+
+static const char* const nullCString = 0;
+
+#define INITIALIZE_PROPERTY_NAME(name) , name(globalData, #name)
+#define INITIALIZE_KEYWORD(name) , name##Keyword(globalData, #name)
+
+CommonIdentifiers::CommonIdentifiers(JSGlobalData* globalData)
+ : nullIdentifier(globalData, nullCString)
+ , emptyIdentifier(globalData, "")
+ , underscoreProto(globalData, "__proto__")
+ , thisIdentifier(globalData, "this")
+ , useStrictIdentifier(globalData, "use strict")
+ JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(INITIALIZE_KEYWORD)
+ JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME)
+{
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/CommonIdentifiers.h b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
new file mode 100644
index 000000000..08d8644b5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/CommonIdentifiers.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 2003, 2007, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef CommonIdentifiers_h
+#define CommonIdentifiers_h
+
+#include "Identifier.h"
+#include <wtf/Noncopyable.h>
+
+// MarkedArgumentBuffer of property names, passed to a macro so we can do set them up various
+// ways without repeating the list.
+#define JSC_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
+ macro(__defineGetter__) \
+ macro(__defineSetter__) \
+ macro(__lookupGetter__) \
+ macro(__lookupSetter__) \
+ macro(apply) \
+ macro(arguments) \
+ macro(bind) \
+ macro(call) \
+ macro(callee) \
+ macro(caller) \
+ macro(compile) \
+ macro(configurable) \
+ macro(constructor) \
+ macro(enumerable) \
+ macro(eval) \
+ macro(exec) \
+ macro(fromCharCode) \
+ macro(global) \
+ macro(get) \
+ macro(hasOwnProperty) \
+ macro(ignoreCase) \
+ macro(index) \
+ macro(input) \
+ macro(isArray) \
+ macro(isPrototypeOf) \
+ macro(length) \
+ macro(message) \
+ macro(multiline) \
+ macro(name) \
+ macro(now) \
+ macro(parse) \
+ macro(propertyIsEnumerable) \
+ macro(prototype) \
+ macro(set) \
+ macro(source) \
+ macro(test) \
+ macro(toExponential) \
+ macro(toFixed) \
+ macro(toISOString) \
+ macro(toJSON) \
+ macro(toLocaleString) \
+ macro(toPrecision) \
+ macro(toString) \
+ macro(UTC) \
+ macro(value) \
+ macro(valueOf) \
+ macro(writable) \
+ macro(displayName) \
+ macro(undefined)
+
+#define JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(macro) \
+ macro(null) \
+ macro(true) \
+ macro(false) \
+ macro(break) \
+ macro(case) \
+ macro(catch) \
+ macro(const) \
+ macro(default) \
+ macro(finally) \
+ macro(for) \
+ macro(instanceof) \
+ macro(new) \
+ macro(var) \
+ macro(continue) \
+ macro(function) \
+ macro(return) \
+ macro(void) \
+ macro(delete) \
+ macro(if) \
+ macro(this) \
+ macro(do) \
+ macro(while) \
+ macro(else) \
+ macro(in) \
+ macro(switch) \
+ macro(throw) \
+ macro(try) \
+ macro(typeof) \
+ macro(with) \
+ macro(debugger) \
+ macro(class) \
+ macro(enum) \
+ macro(export) \
+ macro(extends) \
+ macro(import) \
+ macro(super) \
+ macro(implements) \
+ macro(interface) \
+ macro(let) \
+ macro(package) \
+ macro(private) \
+ macro(protected) \
+ macro(public) \
+ macro(static) \
+ macro(yield)
+
+namespace JSC {
+
+ class CommonIdentifiers {
+ WTF_MAKE_NONCOPYABLE(CommonIdentifiers); WTF_MAKE_FAST_ALLOCATED;
+ private:
+ CommonIdentifiers(JSGlobalData*);
+ friend class JSGlobalData;
+
+ public:
+ const Identifier nullIdentifier;
+ const Identifier emptyIdentifier;
+ const Identifier underscoreProto;
+ const Identifier thisIdentifier;
+ const Identifier useStrictIdentifier;
+
+
+#define JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL(name) const Identifier name##Keyword;
+ JSC_COMMON_IDENTIFIERS_EACH_KEYWORD(JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL)
+#undef JSC_IDENTIFIER_DECLARE_KEYWORD_NAME_GLOBAL
+
+#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/Source/JavaScriptCore/runtime/Completion.cpp b/Source/JavaScriptCore/runtime/Completion.cpp
new file mode 100644
index 000000000..c3d9e6947
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Completion.cpp
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2007 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Completion.h"
+
+#include "CallFrame.h"
+#include "JSGlobalObject.h"
+#include "JSLock.h"
+#include "Interpreter.h"
+#include "Parser.h"
+#include "Debugger.h"
+#include "WTFThreadData.h"
+#include <stdio.h>
+
+namespace JSC {
+
+bool checkSyntax(ExecState* exec, const SourceCode& source, JSValue* returnedException)
+{
+ JSLock lock(exec);
+ ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable());
+
+ ProgramExecutable* program = ProgramExecutable::create(exec, source);
+ JSObject* error = program->checkSyntax(exec);
+ if (error) {
+ if (returnedException)
+ *returnedException = error;
+ return false;
+ }
+
+ return true;
+}
+
+JSValue evaluate(ExecState* exec, ScopeChainNode* scopeChain, const SourceCode& source, JSValue thisValue, JSValue* returnedException)
+{
+ JSLock lock(exec);
+ ASSERT(exec->globalData().identifierTable == wtfThreadData().currentIdentifierTable());
+
+ ProgramExecutable* program = ProgramExecutable::create(exec, source);
+ if (!program) {
+ if (returnedException)
+ *returnedException = exec->globalData().exception;
+
+ exec->globalData().exception = JSValue();
+ return jsUndefined();
+ }
+
+ if (!thisValue || thisValue.isUndefinedOrNull())
+ thisValue = exec->dynamicGlobalObject();
+ JSObject* thisObj = thisValue.toThisObject(exec);
+ JSValue result = exec->interpreter()->execute(program, exec, scopeChain, thisObj);
+
+ if (exec->hadException()) {
+ if (returnedException)
+ *returnedException = exec->exception();
+
+ exec->clearException();
+ return jsUndefined();
+ }
+
+ ASSERT(result);
+ return result;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Completion.h b/Source/JavaScriptCore/runtime/Completion.h
new file mode 100644
index 000000000..c3dbdfc58
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Completion.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Completion_h
+#define Completion_h
+
+#include "JSValue.h"
+
+namespace JSC {
+
+ class ExecState;
+ class ScopeChainNode;
+ class SourceCode;
+
+ bool checkSyntax(ExecState*, const SourceCode&, JSValue* exception = 0);
+ JSValue evaluate(ExecState*, ScopeChainNode*, const SourceCode&, JSValue thisValue = JSValue(), JSValue* exception = 0);
+
+} // namespace JSC
+
+#endif // Completion_h
diff --git a/Source/JavaScriptCore/runtime/ConstructData.cpp b/Source/JavaScriptCore/runtime/ConstructData.cpp
new file mode 100644
index 000000000..5da2a911c
--- /dev/null
+++ b/Source/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 "Executable.h"
+#include "Interpreter.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+
+namespace JSC {
+
+JSObject* construct(ExecState* exec, JSValue constructorObject, ConstructType constructType, const ConstructData& constructData, const ArgList& args)
+{
+ ASSERT(constructType == ConstructTypeJS || constructType == ConstructTypeHost);
+ return exec->interpreter()->executeConstruct(exec, asObject(constructorObject), constructType, constructData, args);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ConstructData.h b/Source/JavaScriptCore/runtime/ConstructData.h
new file mode 100644
index 000000000..cc8f46977
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ConstructData.h
@@ -0,0 +1,63 @@
+/*
+ * 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 "CallData.h"
+#include "JSValue.h"
+
+namespace JSC {
+
+ class ArgList;
+ class ExecState;
+ class FunctionExecutable;
+ class JSObject;
+ class ScopeChainNode;
+
+ enum ConstructType {
+ ConstructTypeNone,
+ ConstructTypeHost,
+ ConstructTypeJS
+ };
+
+ union ConstructData {
+ struct {
+ NativeFunction function;
+ } native;
+ struct {
+ FunctionExecutable* functionExecutable;
+ ScopeChainNode* scopeChain;
+ } js;
+ };
+
+ JSObject* construct(ExecState*, JSValue constructor, ConstructType, const ConstructData&, const ArgList&);
+
+} // namespace JSC
+
+#endif // ConstructData_h
diff --git a/Source/JavaScriptCore/runtime/DateConstructor.cpp b/Source/JavaScriptCore/runtime/DateConstructor.cpp
new file mode 100644
index 000000000..79c5181eb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DateConstructor.cpp
@@ -0,0 +1,229 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ *
+ */
+
+#include "config.h"
+#include "DateConstructor.h"
+
+#include "DateConversion.h"
+#include "DateInstance.h"
+#include "DatePrototype.h"
+#include "JSDateMath.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+#include "ObjectPrototype.h"
+#include <math.h>
+#include <time.h>
+#include <wtf/MathExtras.h>
+
+#if OS(WINCE) && !PLATFORM(QT)
+extern "C" time_t time(time_t* timer); // Provided by libce.
+#endif
+
+#if HAVE(SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+#if HAVE(SYS_TIMEB_H)
+#include <sys/timeb.h>
+#endif
+
+using namespace WTF;
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL dateParse(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState*);
+
+}
+
+#include "DateConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo DateConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::dateConstructorTable, CREATE_METHOD_TABLE(DateConstructor) };
+
+/* Source for DateConstructor.lut.h
+@begin dateConstructorTable
+ parse dateParse DontEnum|Function 1
+ UTC dateUTC DontEnum|Function 7
+ now dateNow DontEnum|Function 0
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(DateConstructor);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(DateConstructor);
+
+DateConstructor::DateConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void DateConstructor::finishCreation(ExecState* exec, DatePrototype* datePrototype)
+{
+ Base::finishCreation(exec->globalData(), Identifier(exec, datePrototype->classInfo()->className));
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, datePrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(7), ReadOnly | DontEnum | DontDelete);
+}
+
+bool DateConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<InternalFunction>(exec, ExecState::dateConstructorTable(exec), jsCast<DateConstructor*>(cell), propertyName, slot);
+}
+
+bool DateConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<InternalFunction>(exec, ExecState::dateConstructorTable(exec), jsCast<DateConstructor*>(object), propertyName, descriptor);
+}
+
+// ECMA 15.9.3
+JSObject* constructDate(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
+{
+ int numArgs = args.size();
+
+ double value;
+
+ if (numArgs == 0) // new Date() ECMA 15.9.3.3
+ value = jsCurrentTime();
+ else if (numArgs == 1) {
+ if (args.at(0).inherits(&DateInstance::s_info))
+ value = asDateInstance(args.at(0))->internalNumber();
+ else {
+ JSValue primitive = args.at(0).toPrimitive(exec);
+ if (primitive.isString())
+ value = parseDate(exec, primitive.getString(exec));
+ else
+ value = primitive.toNumber(exec);
+ }
+ } else {
+ double doubleArguments[7] = {
+ args.at(0).toNumber(exec),
+ args.at(1).toNumber(exec),
+ args.at(2).toNumber(exec),
+ args.at(3).toNumber(exec),
+ args.at(4).toNumber(exec),
+ args.at(5).toNumber(exec),
+ args.at(6).toNumber(exec)
+ };
+ if (!isfinite(doubleArguments[0])
+ || !isfinite(doubleArguments[1])
+ || (numArgs >= 3 && !isfinite(doubleArguments[2]))
+ || (numArgs >= 4 && !isfinite(doubleArguments[3]))
+ || (numArgs >= 5 && !isfinite(doubleArguments[4]))
+ || (numArgs >= 6 && !isfinite(doubleArguments[5]))
+ || (numArgs >= 7 && !isfinite(doubleArguments[6])))
+ value = std::numeric_limits<double>::quiet_NaN();
+ else {
+ GregorianDateTime t;
+ int year = JSC::toInt32(doubleArguments[0]);
+ t.year = (year >= 0 && year <= 99) ? year : year - 1900;
+ t.month = JSC::toInt32(doubleArguments[1]);
+ t.monthDay = (numArgs >= 3) ? JSC::toInt32(doubleArguments[2]) : 1;
+ t.hour = JSC::toInt32(doubleArguments[3]);
+ t.minute = JSC::toInt32(doubleArguments[4]);
+ t.second = JSC::toInt32(doubleArguments[5]);
+ t.isDST = -1;
+ double ms = (numArgs >= 7) ? doubleArguments[6] : 0;
+ value = gregorianDateTimeToMS(exec, t, ms, false);
+ }
+ }
+
+ return DateInstance::create(exec, globalObject->dateStructure(), value);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWithDateConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructDate(exec, asInternalFunction(exec->callee())->globalObject(), args));
+}
+
+ConstructType DateConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithDateConstructor;
+ return ConstructTypeHost;
+}
+
+// ECMA 15.9.2
+static EncodedJSValue JSC_HOST_CALL callDate(ExecState* exec)
+{
+ time_t localTime = time(0);
+ tm localTM;
+ getLocalTime(&localTime, &localTM);
+ GregorianDateTime ts(exec, localTM);
+ DateConversionBuffer date;
+ DateConversionBuffer time;
+ formatDate(ts, date);
+ formatTime(ts, time);
+ return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
+}
+
+CallType DateConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callDate;
+ return CallTypeHost;
+}
+
+static EncodedJSValue JSC_HOST_CALL dateParse(ExecState* exec)
+{
+ return JSValue::encode(jsNumber(parseDate(exec, exec->argument(0).toString(exec))));
+}
+
+static EncodedJSValue JSC_HOST_CALL dateNow(ExecState*)
+{
+ return JSValue::encode(jsNumber(jsCurrentTime()));
+}
+
+static EncodedJSValue JSC_HOST_CALL dateUTC(ExecState* exec)
+{
+ double doubleArguments[7] = {
+ exec->argument(0).toNumber(exec),
+ exec->argument(1).toNumber(exec),
+ exec->argument(2).toNumber(exec),
+ exec->argument(3).toNumber(exec),
+ exec->argument(4).toNumber(exec),
+ exec->argument(5).toNumber(exec),
+ exec->argument(6).toNumber(exec)
+ };
+ int n = exec->argumentCount();
+ if (isnan(doubleArguments[0])
+ || isnan(doubleArguments[1])
+ || (n >= 3 && isnan(doubleArguments[2]))
+ || (n >= 4 && isnan(doubleArguments[3]))
+ || (n >= 5 && isnan(doubleArguments[4]))
+ || (n >= 6 && isnan(doubleArguments[5]))
+ || (n >= 7 && isnan(doubleArguments[6])))
+ return JSValue::encode(jsNaN());
+
+ GregorianDateTime t;
+ int year = JSC::toInt32(doubleArguments[0]);
+ t.year = (year >= 0 && year <= 99) ? year : year - 1900;
+ t.month = JSC::toInt32(doubleArguments[1]);
+ t.monthDay = (n >= 3) ? JSC::toInt32(doubleArguments[2]) : 1;
+ t.hour = JSC::toInt32(doubleArguments[3]);
+ t.minute = JSC::toInt32(doubleArguments[4]);
+ t.second = JSC::toInt32(doubleArguments[5]);
+ double ms = (n >= 7) ? doubleArguments[6] : 0;
+ return JSValue::encode(jsNumber(timeClip(gregorianDateTimeToMS(exec, t, ms, true))));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/DateConstructor.h b/Source/JavaScriptCore/runtime/DateConstructor.h
new file mode 100644
index 000000000..fe6597418
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DateConstructor.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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:
+ typedef InternalFunction Base;
+
+ static DateConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, DatePrototype* datePrototype)
+ {
+ DateConstructor* constructor = new (NotNull, allocateCell<DateConstructor>(*exec->heap())) DateConstructor(globalObject, structure);
+ constructor->finishCreation(exec, datePrototype);
+ return constructor;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(ExecState*, DatePrototype*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+
+ private:
+ DateConstructor(JSGlobalObject*, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ };
+
+ JSObject* constructDate(ExecState*, JSGlobalObject*, const ArgList&);
+
+} // namespace JSC
+
+#endif // DateConstructor_h
diff --git a/Source/JavaScriptCore/runtime/DateConversion.cpp b/Source/JavaScriptCore/runtime/DateConversion.cpp
new file mode 100644
index 000000000..7bc0cbc0f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DateConversion.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#include "config.h"
+#include "DateConversion.h"
+
+#include "CallFrame.h"
+#include "JSDateMath.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
+#include "UString.h"
+#include <wtf/StringExtras.h>
+#include <wtf/text/CString.h>
+
+using namespace WTF;
+
+namespace JSC {
+
+double parseDate(ExecState* exec, const UString &date)
+{
+ if (date == exec->globalData().cachedDateString)
+ return exec->globalData().cachedDateStringValue;
+ double value = parseES5DateFromNullTerminatedCharacters(date.utf8().data());
+ if (isnan(value))
+ value = parseDateFromNullTerminatedCharacters(exec, date.utf8().data());
+ exec->globalData().cachedDateString = date;
+ exec->globalData().cachedDateStringValue = value;
+ return value;
+}
+
+void formatDate(const GregorianDateTime &t, DateConversionBuffer& buffer)
+{
+ snprintf(buffer, DateConversionBufferSize, "%s %s %02d %04d",
+ weekdayName[(t.weekDay + 6) % 7],
+ monthName[t.month], t.monthDay, t.year + 1900);
+}
+
+void formatDateUTCVariant(const GregorianDateTime &t, DateConversionBuffer& buffer)
+{
+ snprintf(buffer, DateConversionBufferSize, "%s, %02d %s %04d",
+ weekdayName[(t.weekDay + 6) % 7],
+ t.monthDay, monthName[t.month], t.year + 1900);
+}
+
+void formatTime(const GregorianDateTime &t, DateConversionBuffer& buffer)
+{
+ int offset = abs(gmtoffset(t));
+ char timeZoneName[70];
+ struct tm gtm = t;
+ strftime(timeZoneName, sizeof(timeZoneName), "%Z", &gtm);
+
+ if (timeZoneName[0]) {
+ snprintf(buffer, DateConversionBufferSize, "%02d:%02d:%02d GMT%c%02d%02d (%s)",
+ t.hour, t.minute, t.second,
+ gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, timeZoneName);
+ } else {
+ snprintf(buffer, DateConversionBufferSize, "%02d:%02d:%02d GMT%c%02d%02d",
+ t.hour, t.minute, t.second,
+ gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60);
+ }
+}
+
+void formatTimeUTC(const GregorianDateTime &t, DateConversionBuffer& buffer)
+{
+ snprintf(buffer, DateConversionBufferSize, "%02d:%02d:%02d GMT", t.hour, t.minute, t.second);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/DateConversion.h b/Source/JavaScriptCore/runtime/DateConversion.h
new file mode 100644
index 000000000..ff32b503d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DateConversion.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ */
+
+#ifndef DateConversion_h
+#define DateConversion_h
+
+#include "UString.h"
+
+namespace JSC {
+
+class ExecState;
+struct GregorianDateTime;
+
+static const unsigned DateConversionBufferSize = 100;
+typedef char DateConversionBuffer[DateConversionBufferSize];
+
+double parseDate(ExecState* exec, const UString&);
+void formatDate(const GregorianDateTime&, DateConversionBuffer&);
+void formatDateUTCVariant(const GregorianDateTime&, DateConversionBuffer&);
+void formatTime(const GregorianDateTime&, DateConversionBuffer&);
+void formatTimeUTC(const GregorianDateTime&, DateConversionBuffer&);
+
+} // namespace JSC
+
+#endif // DateConversion_h
diff --git a/Source/JavaScriptCore/runtime/DateInstance.cpp b/Source/JavaScriptCore/runtime/DateInstance.cpp
new file mode 100644
index 000000000..a502770c8
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DateInstance.cpp
@@ -0,0 +1,93 @@
+/*
+ * 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 "JSDateMath.h"
+#include "JSGlobalObject.h"
+
+#include <math.h>
+#include <wtf/MathExtras.h>
+
+using namespace WTF;
+
+namespace JSC {
+
+const ClassInfo DateInstance::s_info = {"Date", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(DateInstance)};
+
+DateInstance::DateInstance(ExecState* exec, Structure* structure)
+ : JSWrapperObject(exec->globalData(), structure)
+{
+}
+
+void DateInstance::finishCreation(JSGlobalData& globalData)
+{
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+ setInternalValue(globalData, jsNaN());
+}
+
+void DateInstance::finishCreation(JSGlobalData& globalData, double time)
+{
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+ setInternalValue(globalData, jsNumber(timeClip(time)));
+}
+
+void DateInstance::destroy(JSCell* cell)
+{
+ jsCast<DateInstance*>(cell)->DateInstance::~DateInstance();
+}
+
+const GregorianDateTime* DateInstance::calculateGregorianDateTime(ExecState* exec) const
+{
+ double milli = internalNumber();
+ if (isnan(milli))
+ return 0;
+
+ if (!m_data)
+ m_data = exec->globalData().dateInstanceCache.add(milli);
+
+ if (m_data->m_gregorianDateTimeCachedForMS != milli) {
+ msToGregorianDateTime(exec, milli, false, m_data->m_cachedGregorianDateTime);
+ m_data->m_gregorianDateTimeCachedForMS = milli;
+ }
+ return &m_data->m_cachedGregorianDateTime;
+}
+
+const GregorianDateTime* DateInstance::calculateGregorianDateTimeUTC(ExecState* exec) const
+{
+ double milli = internalNumber();
+ if (isnan(milli))
+ return 0;
+
+ if (!m_data)
+ m_data = exec->globalData().dateInstanceCache.add(milli);
+
+ if (m_data->m_gregorianDateTimeUTCCachedForMS != milli) {
+ msToGregorianDateTime(exec, milli, true, m_data->m_cachedGregorianDateTimeUTC);
+ m_data->m_gregorianDateTimeUTCCachedForMS = milli;
+ }
+ return &m_data->m_cachedGregorianDateTimeUTC;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/DateInstance.h b/Source/JavaScriptCore/runtime/DateInstance.h
new file mode 100644
index 000000000..3edfb0970
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DateInstance.h
@@ -0,0 +1,97 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef DateInstance_h
+#define DateInstance_h
+
+#include "JSWrapperObject.h"
+
+namespace WTF {
+ struct GregorianDateTime;
+}
+
+namespace JSC {
+
+ class DateInstance : public JSWrapperObject {
+ protected:
+ DateInstance(ExecState*, Structure*);
+ void finishCreation(JSGlobalData&);
+ void finishCreation(JSGlobalData&, double);
+
+ static void destroy(JSCell*);
+
+ public:
+ typedef JSWrapperObject Base;
+
+ static DateInstance* create(ExecState* exec, Structure* structure, double date)
+ {
+ DateInstance* instance = new (NotNull, allocateCell<DateInstance>(*exec->heap())) DateInstance(exec, structure);
+ instance->finishCreation(exec->globalData(), date);
+ return instance;
+ }
+
+ static DateInstance* create(ExecState* exec, Structure* structure)
+ {
+ DateInstance* instance = new (NotNull, allocateCell<DateInstance>(*exec->heap())) DateInstance(exec, structure);
+ instance->finishCreation(exec->globalData());
+ return instance;
+ }
+
+ double internalNumber() const { return internalValue().asNumber(); }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ const GregorianDateTime* gregorianDateTime(ExecState* exec) const
+ {
+ if (m_data && m_data->m_gregorianDateTimeCachedForMS == internalNumber())
+ return &m_data->m_cachedGregorianDateTime;
+ return calculateGregorianDateTime(exec);
+ }
+
+ const GregorianDateTime* gregorianDateTimeUTC(ExecState* exec) const
+ {
+ if (m_data && m_data->m_gregorianDateTimeUTCCachedForMS == internalNumber())
+ return &m_data->m_cachedGregorianDateTimeUTC;
+ return calculateGregorianDateTimeUTC(exec);
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ private:
+ const GregorianDateTime* calculateGregorianDateTime(ExecState*) const;
+ const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const;
+
+ mutable RefPtr<DateInstanceData> m_data;
+ };
+
+ DateInstance* asDateInstance(JSValue);
+
+ inline DateInstance* asDateInstance(JSValue value)
+ {
+ ASSERT(asObject(value)->inherits(&DateInstance::s_info));
+ return static_cast<DateInstance*>(asObject(value));
+ }
+
+} // namespace JSC
+
+#endif // DateInstance_h
diff --git a/Source/JavaScriptCore/runtime/DateInstanceCache.h b/Source/JavaScriptCore/runtime/DateInstanceCache.h
new file mode 100644
index 000000000..153582f67
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DateInstanceCache.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef DateInstanceCache_h
+#define DateInstanceCache_h
+
+#include "JSDateMath.h"
+#include <wtf/FixedArray.h>
+#include <wtf/HashFunctions.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+namespace JSC {
+
+ class DateInstanceData : public RefCounted<DateInstanceData> {
+ public:
+ static PassRefPtr<DateInstanceData> create() { return adoptRef(new DateInstanceData); }
+
+ double m_gregorianDateTimeCachedForMS;
+ GregorianDateTime m_cachedGregorianDateTime;
+ double m_gregorianDateTimeUTCCachedForMS;
+ GregorianDateTime m_cachedGregorianDateTimeUTC;
+
+ private:
+ DateInstanceData()
+ : m_gregorianDateTimeCachedForMS(std::numeric_limits<double>::quiet_NaN())
+ , m_gregorianDateTimeUTCCachedForMS(std::numeric_limits<double>::quiet_NaN())
+ {
+ }
+ };
+
+ class DateInstanceCache {
+ public:
+ DateInstanceCache()
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ for (size_t i = 0; i < cacheSize; ++i)
+ m_cache[i].key = std::numeric_limits<double>::quiet_NaN();
+ }
+
+ DateInstanceData* add(double d)
+ {
+ CacheEntry& entry = lookup(d);
+ if (d == entry.key)
+ return entry.value.get();
+
+ entry.key = d;
+ entry.value = DateInstanceData::create();
+ return entry.value.get();
+ }
+
+ private:
+ static const size_t cacheSize = 16;
+
+ struct CacheEntry {
+ double key;
+ RefPtr<DateInstanceData> value;
+ };
+
+ CacheEntry& lookup(double d) { return m_cache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; }
+
+ FixedArray<CacheEntry, cacheSize> m_cache;
+ };
+
+} // namespace JSC
+
+#endif // DateInstanceCache_h
diff --git a/Source/JavaScriptCore/runtime/DatePrototype.cpp b/Source/JavaScriptCore/runtime/DatePrototype.cpp
new file mode 100644
index 000000000..96dea01db
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DatePrototype.cpp
@@ -0,0 +1,1109 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008, 2009 Torch Mobile, Inc. All rights reserved.
+ * Copyright (C) 2010 Torch Mobile (Beijing) Co. Ltd. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ *
+ */
+
+#include "config.h"
+#include "DatePrototype.h"
+
+#include "DateConversion.h"
+#include "DateInstance.h"
+#include "Error.h"
+#include "JSDateMath.h"
+#include "JSGlobalObject.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+#include "Lookup.h"
+#include "ObjectPrototype.h"
+
+#if !PLATFORM(MAC) && HAVE(LANGINFO_H)
+#include <langinfo.h>
+#endif
+
+#include <limits.h>
+#include <locale.h>
+#include <math.h>
+#include <stdlib.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) || PLATFORM(IOS)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+#if OS(WINCE) && !PLATFORM(QT)
+extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t); //provided by libce
+#endif
+
+using namespace WTF;
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(DatePrototype);
+
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState*);
+
+}
+
+#include "DatePrototype.lut.h"
+
+namespace JSC {
+
+enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
+
+#if PLATFORM(MAC) || PLATFORM(IOS)
+
+// FIXME: Since this is superior to the strftime-based version, why limit this to PLATFORM(MAC)?
+// Instead we should consider using this whenever USE(CF) is true.
+
+static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
+{
+ if (string == "short")
+ return kCFDateFormatterShortStyle;
+ if (string == "medium")
+ return kCFDateFormatterMediumStyle;
+ if (string == "long")
+ return kCFDateFormatterLongStyle;
+ if (string == "full")
+ return kCFDateFormatterFullStyle;
+ return defaultStyle;
+}
+
+static JSCell* formatLocaleDate(ExecState* exec, DateInstance*, double timeInMilliseconds, LocaleDateTimeFormat format)
+{
+ CFDateFormatterStyle dateStyle = (format != LocaleTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
+ CFDateFormatterStyle timeStyle = (format != LocaleDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
+
+ bool useCustomFormat = false;
+ UString customFormatString;
+
+ UString arg0String = exec->argument(0).toString(exec);
+ if (arg0String == "custom" && !exec->argument(1).isUndefined()) {
+ useCustomFormat = true;
+ customFormatString = exec->argument(1).toString(exec);
+ } else if (format == LocaleDateAndTime && !exec->argument(1).isUndefined()) {
+ dateStyle = styleFromArgString(arg0String, dateStyle);
+ timeStyle = styleFromArgString(exec->argument(1).toString(exec), timeStyle);
+ } else if (format != LocaleTime && !exec->argument(0).isUndefined())
+ dateStyle = styleFromArgString(arg0String, dateStyle);
+ else if (format != LocaleDate && !exec->argument(0).isUndefined())
+ timeStyle = styleFromArgString(arg0String, timeStyle);
+
+ CFLocaleRef locale = CFLocaleCopyCurrent();
+ CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
+ CFRelease(locale);
+
+ if (useCustomFormat) {
+ CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, customFormatString.characters(), customFormatString.length());
+ CFDateFormatterSetFormat(formatter, customFormatCFString);
+ CFRelease(customFormatCFString);
+ }
+
+ CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, floor(timeInMilliseconds / msPerSecond) - kCFAbsoluteTimeIntervalSince1970);
+
+ CFRelease(formatter);
+
+ // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
+ // That's not great error handling, but it just won't happen so it doesn't matter.
+ UChar buffer[200];
+ const size_t bufferLength = WTF_ARRAY_LENGTH(buffer);
+ size_t length = CFStringGetLength(string);
+ ASSERT(length <= bufferLength);
+ if (length > bufferLength)
+ length = bufferLength;
+ CFStringGetCharacters(string, CFRangeMake(0, length), buffer);
+
+ CFRelease(string);
+
+ return jsNontrivialString(exec, UString(buffer, length));
+}
+
+#else // !PLATFORM(MAC) && !PLATFORM(IOS)
+
+static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, LocaleDateTimeFormat format)
+{
+#if HAVE(LANGINFO_H)
+ static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT };
+#elif (OS(WINCE) && !PLATFORM(QT))
+ // strftime() does not support '#' on WinCE
+ static const char* const formatStrings[] = { "%c", "%x", "%X" };
+#else
+ static const char* const formatStrings[] = { "%#c", "%#x", "%X" };
+#endif
+
+ // Offset year if needed
+ struct tm localTM = gdt;
+ int year = gdt.year + 1900;
+ bool yearNeedsOffset = year < 1900 || year > 2038;
+ if (yearNeedsOffset)
+ localTM.tm_year = equivalentYearForDST(year) - 1900;
+
+#if HAVE(LANGINFO_H)
+ // We do not allow strftime to generate dates with 2-digits years,
+ // both to avoid ambiguity, and a crash in strncpy, for years that
+ // need offset.
+ char* formatString = strdup(nl_langinfo(formats[format]));
+ char* yPos = strchr(formatString, 'y');
+ if (yPos)
+ *yPos = 'Y';
+#endif
+
+ // Do the formatting
+ const int bufsize = 128;
+ char timebuffer[bufsize];
+
+#if HAVE(LANGINFO_H)
+ size_t ret = strftime(timebuffer, bufsize, formatString, &localTM);
+ free(formatString);
+#else
+ size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
+#endif
+
+ if (ret == 0)
+ return jsEmptyString(exec);
+
+ // Copy original into the buffer
+ if (yearNeedsOffset && format != LocaleTime) {
+ static const int yearLen = 5; // FIXME will be a problem in the year 10,000
+ char yearString[yearLen];
+
+ snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
+ char* yearLocation = strstr(timebuffer, yearString);
+ snprintf(yearString, yearLen, "%d", year);
+
+ strncpy(yearLocation, yearString, yearLen - 1);
+ }
+
+ // Convert multi-byte result to UNICODE.
+ // If __STDC_ISO_10646__ is defined, wide character represents
+ // UTF-16 (or UTF-32) code point. In most modern Unix like system
+ // (e.g. Linux with glibc 2.2 and above) the macro is defined,
+ // and wide character represents UTF-32 code point.
+ // Here we static_cast potential UTF-32 to UTF-16, it should be
+ // safe because date and (or) time related characters in different languages
+ // should be in UNICODE BMP. If mbstowcs fails, we just fall
+ // back on using multi-byte result as-is.
+#ifdef __STDC_ISO_10646__
+ UChar buffer[bufsize];
+ wchar_t tempbuffer[bufsize];
+ size_t length = mbstowcs(tempbuffer, timebuffer, bufsize - 1);
+ if (length != static_cast<size_t>(-1)) {
+ for (size_t i = 0; i < length; ++i)
+ buffer[i] = static_cast<UChar>(tempbuffer[i]);
+ return jsNontrivialString(exec, UString(buffer, length));
+ }
+#endif
+
+ return jsNontrivialString(exec, timebuffer);
+}
+
+static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format)
+{
+ const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return jsNontrivialString(exec, "Invalid Date");
+ return formatLocaleDate(exec, *gregorianDateTime, format);
+}
+
+#endif // !PLATFORM(MAC) && !PLATFORM(IOS)
+
+// 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, int maxArgs, double* ms, GregorianDateTime* t)
+{
+ double milliseconds = 0;
+ bool ok = true;
+ int idx = 0;
+ int numArgs = exec->argumentCount();
+
+ // JS allows extra trailing arguments -- ignore them
+ if (numArgs > maxArgs)
+ numArgs = maxArgs;
+
+ // hours
+ if (maxArgs >= 4 && idx < numArgs) {
+ t->hour = 0;
+ double hours = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(hours);
+ milliseconds += hours * msPerHour;
+ }
+
+ // minutes
+ if (maxArgs >= 3 && idx < numArgs && ok) {
+ t->minute = 0;
+ double minutes = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(minutes);
+ milliseconds += minutes * msPerMinute;
+ }
+
+ // seconds
+ if (maxArgs >= 2 && idx < numArgs && ok) {
+ t->second = 0;
+ double seconds = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(seconds);
+ milliseconds += seconds * msPerSecond;
+ }
+
+ if (!ok)
+ return false;
+
+ // milliseconds
+ if (idx < numArgs) {
+ double millis = exec->argument(idx).toIntegerPreserveNaN(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, int maxArgs, double *ms, GregorianDateTime *t)
+{
+ int idx = 0;
+ bool ok = true;
+ int numArgs = exec->argumentCount();
+
+ // JS allows extra trailing arguments -- ignore them
+ if (numArgs > maxArgs)
+ numArgs = maxArgs;
+
+ // years
+ if (maxArgs >= 3 && idx < numArgs) {
+ double years = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(years);
+ t->year = toInt32(years - 1900);
+ }
+ // months
+ if (maxArgs >= 2 && idx < numArgs && ok) {
+ double months = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(months);
+ t->month = toInt32(months);
+ }
+ // days
+ if (idx < numArgs && ok) {
+ double days = exec->argument(idx++).toIntegerPreserveNaN(exec);
+ ok = isfinite(days);
+ t->monthDay = 0;
+ *ms += days * msPerDay;
+ }
+
+ return ok;
+}
+
+const ClassInfo DatePrototype::s_info = {"Date", &DateInstance::s_info, 0, ExecState::dateTable, CREATE_METHOD_TABLE(DatePrototype)};
+
+/* Source for DatePrototype.lut.h
+@begin dateTable
+ toString dateProtoFuncToString DontEnum|Function 0
+ toISOString dateProtoFuncToISOString DontEnum|Function 0
+ toUTCString dateProtoFuncToUTCString DontEnum|Function 0
+ toDateString dateProtoFuncToDateString DontEnum|Function 0
+ toTimeString dateProtoFuncToTimeString DontEnum|Function 0
+ toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0
+ toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0
+ toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0
+ valueOf dateProtoFuncGetTime DontEnum|Function 0
+ getTime dateProtoFuncGetTime DontEnum|Function 0
+ getFullYear dateProtoFuncGetFullYear DontEnum|Function 0
+ getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0
+ toGMTString dateProtoFuncToGMTString DontEnum|Function 0
+ getMonth dateProtoFuncGetMonth DontEnum|Function 0
+ getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0
+ getDate dateProtoFuncGetDate DontEnum|Function 0
+ getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0
+ getDay dateProtoFuncGetDay DontEnum|Function 0
+ getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0
+ getHours dateProtoFuncGetHours DontEnum|Function 0
+ getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0
+ getMinutes dateProtoFuncGetMinutes DontEnum|Function 0
+ getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0
+ getSeconds dateProtoFuncGetSeconds DontEnum|Function 0
+ getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0
+ getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0
+ getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0
+ getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0
+ setTime dateProtoFuncSetTime DontEnum|Function 1
+ setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1
+ setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1
+ setSeconds dateProtoFuncSetSeconds DontEnum|Function 2
+ setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2
+ setMinutes dateProtoFuncSetMinutes DontEnum|Function 3
+ setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3
+ setHours dateProtoFuncSetHours DontEnum|Function 4
+ setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4
+ setDate dateProtoFuncSetDate DontEnum|Function 1
+ setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1
+ setMonth dateProtoFuncSetMonth DontEnum|Function 2
+ setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2
+ setFullYear dateProtoFuncSetFullYear DontEnum|Function 3
+ setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3
+ setYear dateProtoFuncSetYear DontEnum|Function 1
+ getYear dateProtoFuncGetYear DontEnum|Function 0
+ toJSON dateProtoFuncToJSON DontEnum|Function 1
+@end
+*/
+
+// ECMA 15.9.4
+
+DatePrototype::DatePrototype(ExecState* exec, Structure* structure)
+ : DateInstance(exec, structure)
+{
+}
+
+void DatePrototype::finishCreation(ExecState* exec, JSGlobalObject*)
+{
+ Base::finishCreation(exec->globalData());
+ ASSERT(inherits(&s_info));
+
+ // The constructor will be added later, after DateConstructor has been built.
+}
+
+bool DatePrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), jsCast<DatePrototype*>(cell), propertyName, slot);
+}
+
+bool DatePrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), jsCast<DatePrototype*>(object), propertyName, descriptor);
+}
+
+// Functions
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
+ DateConversionBuffer date;
+ DateConversionBuffer time;
+ formatDate(*gregorianDateTime, date);
+ formatTime(*gregorianDateTime, time);
+ return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
+ DateConversionBuffer date;
+ DateConversionBuffer time;
+ formatDateUTCVariant(*gregorianDateTime, date);
+ formatTimeUTC(*gregorianDateTime, time);
+ return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+ if (!isfinite(thisDateObj->internalNumber()))
+ return throwVMError(exec, createRangeError(exec, "Invalid Date"));
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
+ // Maximum amount of space we need in buffer: 7 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds)
+ // 6 for formatting and one for null termination = 28. We add one extra character to allow us to force null termination.
+ char buffer[29];
+ // If the year is outside the bounds of 0 and 9999 inclusive we want to use the extended year format (ES 15.9.1.15.1).
+ int ms = static_cast<int>(fmod(thisDateObj->internalNumber(), msPerSecond));
+ if (ms < 0)
+ ms += msPerSecond;
+ if (gregorianDateTime->year > 8099 || gregorianDateTime->year < -1900)
+ snprintf(buffer, sizeof(buffer) - 1, "%+07d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, ms);
+ else
+ snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, ms);
+ buffer[sizeof(buffer) - 1] = 0;
+ return JSValue::encode(jsNontrivialString(exec, buffer));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
+ DateConversionBuffer date;
+ formatDate(*gregorianDateTime, date);
+ return JSValue::encode(jsNontrivialString(exec, date));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
+ DateConversionBuffer time;
+ formatTime(*gregorianDateTime, time);
+ return JSValue::encode(jsNontrivialString(exec, time));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+ return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+ return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+ return JSValue::encode(formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ return JSValue::encode(asDateInstance(thisValue)->internalValue());
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(1900 + gregorianDateTime->year));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNontrivialString(exec, "Invalid Date"));
+ DateConversionBuffer date;
+ DateConversionBuffer time;
+ formatDateUTCVariant(*gregorianDateTime, date);
+ formatTimeUTC(*gregorianDateTime, time);
+ return JSValue::encode(jsMakeNontrivialString(exec, date, " ", time));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->month));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->month));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->monthDay));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->weekDay));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->hour));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->hour));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->minute));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->minute));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->second));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(gregorianDateTime->second));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+ double milli = thisDateObj->internalNumber();
+ if (isnan(milli))
+ return JSValue::encode(jsNaN());
+
+ double secs = floor(milli / msPerSecond);
+ double ms = milli - secs * msPerSecond;
+ return JSValue::encode(jsNumber(ms));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+ double milli = thisDateObj->internalNumber();
+ if (isnan(milli))
+ return JSValue::encode(jsNaN());
+
+ double secs = floor(milli / msPerSecond);
+ double ms = milli - secs * msPerSecond;
+ return JSValue::encode(jsNumber(ms));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(-gregorianDateTime->utcOffset / minutesPerHour));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ double milli = timeClip(exec->argument(0).toNumber(exec));
+ JSValue result = jsNumber(milli);
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+}
+
+static EncodedJSValue setNewValueFromTimeArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+ double milli = thisDateObj->internalNumber();
+
+ if (!exec->argumentCount() || isnan(milli)) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+ }
+
+ double secs = floor(milli / msPerSecond);
+ double ms = milli - secs * msPerSecond;
+
+ const GregorianDateTime* other = inputIsUTC
+ ? thisDateObj->gregorianDateTimeUTC(exec)
+ : thisDateObj->gregorianDateTime(exec);
+ if (!other)
+ return JSValue::encode(jsNaN());
+
+ GregorianDateTime gregorianDateTime;
+ gregorianDateTime.copyFrom(*other);
+ if (!fillStructuresUsingTimeArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+ }
+
+ JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+}
+
+static EncodedJSValue setNewValueFromDateArgs(ExecState* exec, int numArgsToUse, bool inputIsUTC)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+ if (!exec->argumentCount()) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+ }
+
+ double milli = thisDateObj->internalNumber();
+ double ms = 0;
+
+ GregorianDateTime gregorianDateTime;
+ if (numArgsToUse == 3 && isnan(milli))
+ msToGregorianDateTime(exec, 0, true, gregorianDateTime);
+ else {
+ ms = milli - floor(milli / msPerSecond) * msPerSecond;
+ const GregorianDateTime* other = inputIsUTC
+ ? thisDateObj->gregorianDateTimeUTC(exec)
+ : thisDateObj->gregorianDateTime(exec);
+ if (!other)
+ return JSValue::encode(jsNaN());
+ gregorianDateTime.copyFrom(*other);
+ }
+
+ if (!fillStructuresUsingDateArgs(exec, numArgsToUse, &ms, &gregorianDateTime)) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+ }
+
+ JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC));
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMilliSeconds(ExecState* exec)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMilliseconds(ExecState* exec)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromTimeArgs(exec, 1, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetSeconds(ExecState* exec)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCSeconds(ExecState* exec)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromTimeArgs(exec, 2, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMinutes(ExecState* exec)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMinutes(ExecState* exec)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromTimeArgs(exec, 3, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetHours(ExecState* exec)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCHours(ExecState* exec)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromTimeArgs(exec, 4, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetDate(ExecState* exec)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromDateArgs(exec, 1, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCDate(ExecState* exec)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromDateArgs(exec, 1, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetMonth(ExecState* exec)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromDateArgs(exec, 2, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCMonth(ExecState* exec)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromDateArgs(exec, 2, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetFullYear(ExecState* exec)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromDateArgs(exec, 3, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromDateArgs(exec, 3, inputIsUTC);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+ if (!exec->argumentCount()) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+ }
+
+ double milli = thisDateObj->internalNumber();
+ double ms = 0;
+
+ GregorianDateTime gregorianDateTime;
+ if (isnan(milli))
+ // Based on ECMA 262 B.2.5 (setYear)
+ // the time must be reset to +0 if it is NaN.
+ msToGregorianDateTime(exec, 0, true, gregorianDateTime);
+ else {
+ double secs = floor(milli / msPerSecond);
+ ms = milli - secs * msPerSecond;
+ if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec))
+ gregorianDateTime.copyFrom(*other);
+ }
+
+ double year = exec->argument(0).toIntegerPreserveNaN(exec);
+ if (!isfinite(year)) {
+ JSValue result = jsNaN();
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+ }
+
+ gregorianDateTime.year = toInt32((year > 99 || year < 0) ? year - 1900 : year);
+ JSValue result = jsNumber(gregorianDateTimeToMS(exec, gregorianDateTime, ms, false));
+ thisDateObj->setInternalValue(exec->globalData(), result);
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&DateInstance::s_info))
+ return throwVMTypeError(exec);
+
+ DateInstance* thisDateObj = asDateInstance(thisValue);
+
+ const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec);
+ if (!gregorianDateTime)
+ return JSValue::encode(jsNaN());
+
+ // NOTE: IE returns the full year even in getYear.
+ return JSValue::encode(jsNumber(gregorianDateTime->year));
+}
+
+EncodedJSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ JSObject* object = thisValue.toThisObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+
+ JSValue toISOValue = object->get(exec, exec->globalData().propertyNames->toISOString);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+
+ CallData callData;
+ CallType callType = getCallData(toISOValue, callData);
+ if (callType == CallTypeNone)
+ return throwVMError(exec, createTypeError(exec, "toISOString is not a function"));
+
+ JSValue result = call(exec, asObject(toISOValue), callType, callData, object, exec->emptyList());
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ if (result.isObject())
+ return throwVMError(exec, createTypeError(exec, "toISOString did not return a primitive value"));
+ return JSValue::encode(result);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/DatePrototype.h b/Source/JavaScriptCore/runtime/DatePrototype.h
new file mode 100644
index 000000000..90eec28a1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/DatePrototype.h
@@ -0,0 +1,61 @@
+/*
+ * 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 {
+ private:
+ DatePrototype(ExecState*, Structure*);
+
+ public:
+ typedef DateInstance Base;
+
+ static DatePrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ DatePrototype* prototype = new (NotNull, allocateCell<DatePrototype>(*exec->heap())) DatePrototype(exec, structure);
+ prototype->finishCreation(exec, globalObject);
+ return prototype;
+ }
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(ExecState*, JSGlobalObject*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | DateInstance::StructureFlags;
+ };
+
+} // namespace JSC
+
+#endif // DatePrototype_h
diff --git a/Source/JavaScriptCore/runtime/Error.cpp b/Source/JavaScriptCore/runtime/Error.cpp
new file mode 100644
index 000000000..24f5da4f2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Error.cpp
@@ -0,0 +1,178 @@
+/*
+ * 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 "FunctionPrototype.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "JSObject.h"
+#include "JSString.h"
+#include "NativeErrorConstructor.h"
+#include "SourceCode.h"
+
+namespace JSC {
+
+static const char* linePropertyName = "line";
+static const char* sourceIdPropertyName = "sourceId";
+static const char* sourceURLPropertyName = "sourceURL";
+
+JSObject* createError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(globalObject->globalData(), globalObject->errorStructure(), message);
+}
+
+JSObject* createEvalError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(globalObject->globalData(), globalObject->evalErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createRangeError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(globalObject->globalData(), globalObject->rangeErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createReferenceError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(globalObject->globalData(), globalObject->referenceErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createSyntaxError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(globalObject->globalData(), globalObject->syntaxErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createTypeError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(globalObject->globalData(), globalObject->typeErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createURIError(JSGlobalObject* globalObject, const UString& message)
+{
+ ASSERT(!message.isEmpty());
+ return ErrorInstance::create(globalObject->globalData(), globalObject->URIErrorConstructor()->errorStructure(), message);
+}
+
+JSObject* createError(ExecState* exec, const UString& message)
+{
+ return createError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createEvalError(ExecState* exec, const UString& message)
+{
+ return createEvalError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createRangeError(ExecState* exec, const UString& message)
+{
+ return createRangeError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createReferenceError(ExecState* exec, const UString& message)
+{
+ return createReferenceError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createSyntaxError(ExecState* exec, const UString& message)
+{
+ return createSyntaxError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createTypeError(ExecState* exec, const UString& message)
+{
+ return createTypeError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* createURIError(ExecState* exec, const UString& message)
+{
+ return createURIError(exec->lexicalGlobalObject(), message);
+}
+
+JSObject* addErrorInfo(JSGlobalData* globalData, JSObject* error, int line, const SourceCode& source)
+{
+ intptr_t sourceID = source.provider()->asID();
+ const UString& sourceURL = source.provider()->url();
+
+ if (line != -1)
+ error->putWithAttributes(globalData, Identifier(globalData, linePropertyName), jsNumber(line), ReadOnly | DontDelete);
+ if (sourceID != -1)
+ error->putWithAttributes(globalData, Identifier(globalData, sourceIdPropertyName), jsNumber((double)sourceID), ReadOnly | DontDelete);
+ if (!sourceURL.isNull())
+ error->putWithAttributes(globalData, Identifier(globalData, sourceURLPropertyName), jsString(globalData, sourceURL), ReadOnly | DontDelete);
+
+ return error;
+}
+
+JSObject* addErrorInfo(ExecState* exec, JSObject* error, int line, const SourceCode& source)
+{
+ return addErrorInfo(&exec->globalData(), error, line, source);
+}
+
+bool hasErrorInfo(ExecState* exec, JSObject* error)
+{
+ return error->hasProperty(exec, Identifier(exec, linePropertyName))
+ || error->hasProperty(exec, Identifier(exec, sourceIdPropertyName))
+ || error->hasProperty(exec, Identifier(exec, sourceURLPropertyName));
+}
+
+JSValue throwError(ExecState* exec, JSValue error)
+{
+ exec->globalData().exception = error;
+ return error;
+}
+
+JSObject* throwError(ExecState* exec, JSObject* error)
+{
+ exec->globalData().exception = error;
+ return error;
+}
+
+JSObject* throwTypeError(ExecState* exec)
+{
+ return throwError(exec, createTypeError(exec, "Type error"));
+}
+
+JSObject* throwSyntaxError(ExecState* exec)
+{
+ return throwError(exec, createSyntaxError(exec, "Syntax error"));
+}
+
+ASSERT_CLASS_FITS_IN_CELL(StrictModeTypeErrorFunction);
+
+const ClassInfo StrictModeTypeErrorFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(StrictModeTypeErrorFunction) };
+
+void StrictModeTypeErrorFunction::destroy(JSCell* cell)
+{
+ jsCast<StrictModeTypeErrorFunction*>(cell)->StrictModeTypeErrorFunction::~StrictModeTypeErrorFunction();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Error.h b/Source/JavaScriptCore/runtime/Error.h
new file mode 100644
index 000000000..b807d4ab4
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Error.h
@@ -0,0 +1,132 @@
+/*
+ * 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 "InternalFunction.h"
+#include "JSObject.h"
+#include <stdint.h>
+
+namespace JSC {
+
+ class ExecState;
+ class JSGlobalData;
+ class JSGlobalObject;
+ class JSObject;
+ class SourceCode;
+ class Structure;
+ class UString;
+
+ // Methods to create a range of internal errors.
+ JSObject* createError(JSGlobalObject*, const UString&);
+ JSObject* createEvalError(JSGlobalObject*, const UString&);
+ JSObject* createRangeError(JSGlobalObject*, const UString&);
+ JSObject* createReferenceError(JSGlobalObject*, const UString&);
+ JSObject* createSyntaxError(JSGlobalObject*, const UString&);
+ JSObject* createTypeError(JSGlobalObject*, const UString&);
+ JSObject* createURIError(JSGlobalObject*, const UString&);
+ // ExecState wrappers.
+ JSObject* createError(ExecState*, const UString&);
+ JSObject* createEvalError(ExecState*, const UString&);
+ JSObject* createRangeError(ExecState*, const UString&);
+ JSObject* createReferenceError(ExecState*, const UString&);
+ JSObject* createSyntaxError(ExecState*, const UString&);
+ JSObject* createTypeError(ExecState*, const UString&);
+ JSObject* createURIError(ExecState*, const UString&);
+
+ // Methods to add
+ bool hasErrorInfo(ExecState*, JSObject* error);
+ JSObject* addErrorInfo(JSGlobalData*, JSObject* error, int line, const SourceCode&);
+ // ExecState wrappers.
+ JSObject* addErrorInfo(ExecState*, JSObject* error, int line, const SourceCode&);
+
+ // Methods to throw Errors.
+ JSValue throwError(ExecState*, JSValue);
+ JSObject* throwError(ExecState*, JSObject*);
+
+ // Convenience wrappers, create an throw an exception with a default message.
+ JSObject* throwTypeError(ExecState*);
+ JSObject* throwSyntaxError(ExecState*);
+
+ // Convenience wrappers, wrap result as an EncodedJSValue.
+ inline EncodedJSValue throwVMError(ExecState* exec, JSValue error) { return JSValue::encode(throwError(exec, error)); }
+ inline EncodedJSValue throwVMTypeError(ExecState* exec) { return JSValue::encode(throwTypeError(exec)); }
+
+ class StrictModeTypeErrorFunction : public InternalFunction {
+ private:
+ StrictModeTypeErrorFunction(JSGlobalObject* globalObject, Structure* structure, const UString& message)
+ : InternalFunction(globalObject, structure)
+ , m_message(message)
+ {
+ }
+
+ static void destroy(JSCell*);
+
+ public:
+ typedef InternalFunction Base;
+
+ static StrictModeTypeErrorFunction* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, const UString& message)
+ {
+ StrictModeTypeErrorFunction* function = new (NotNull, allocateCell<StrictModeTypeErrorFunction>(*exec->heap())) StrictModeTypeErrorFunction(globalObject, structure, message);
+ function->finishCreation(exec->globalData(), exec->globalData().propertyNames->emptyIdentifier);
+ return function;
+ }
+
+ static EncodedJSValue JSC_HOST_CALL constructThrowTypeError(ExecState* exec)
+ {
+ throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
+ return JSValue::encode(jsNull());
+ }
+
+ static ConstructType getConstructData(JSCell*, ConstructData& constructData)
+ {
+ constructData.native.function = constructThrowTypeError;
+ return ConstructTypeHost;
+ }
+
+ static EncodedJSValue JSC_HOST_CALL callThrowTypeError(ExecState* exec)
+ {
+ throwTypeError(exec, static_cast<StrictModeTypeErrorFunction*>(exec->callee())->m_message);
+ return JSValue::encode(jsNull());
+ }
+
+ static CallType getCallData(JSCell*, CallData& callData)
+ {
+ callData.native.function = callThrowTypeError;
+ return CallTypeHost;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ private:
+ UString m_message;
+ };
+
+} // namespace JSC
+
+#endif // Error_h
diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.cpp b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp
new file mode 100644
index 000000000..c8f93ba32
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ErrorConstructor.cpp
@@ -0,0 +1,76 @@
+/*
+ * 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);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(ErrorConstructor);
+
+const ClassInfo ErrorConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(ErrorConstructor) };
+
+ErrorConstructor::ErrorConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void ErrorConstructor::finishCreation(ExecState* exec, ErrorPrototype* errorPrototype)
+{
+ Base::finishCreation(exec->globalData(), Identifier(exec, errorPrototype->classInfo()->className));
+ // ECMA 15.11.3.1 Error.prototype
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, errorPrototype, DontEnum | DontDelete | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum);
+}
+
+// ECMA 15.9.3
+
+static EncodedJSValue JSC_HOST_CALL constructWithErrorConstructor(ExecState* exec)
+{
+ JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
+ Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure();
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message));
+}
+
+ConstructType ErrorConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithErrorConstructor;
+ return ConstructTypeHost;
+}
+
+static EncodedJSValue JSC_HOST_CALL callErrorConstructor(ExecState* exec)
+{
+ JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
+ Structure* errorStructure = asInternalFunction(exec->callee())->globalObject()->errorStructure();
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message));
+}
+
+CallType ErrorConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callErrorConstructor;
+ return CallTypeHost;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ErrorConstructor.h b/Source/JavaScriptCore/runtime/ErrorConstructor.h
new file mode 100644
index 000000000..58399a9bc
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ErrorConstructor.h
@@ -0,0 +1,60 @@
+/*
+ * 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:
+ typedef InternalFunction Base;
+
+ static ErrorConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ErrorPrototype* errorPrototype)
+ {
+ ErrorConstructor* constructor = new (NotNull, allocateCell<ErrorConstructor>(*exec->heap())) ErrorConstructor(globalObject, structure);
+ constructor->finishCreation(exec, errorPrototype);
+ return constructor;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(ExecState*, ErrorPrototype*);
+
+ private:
+ ErrorConstructor(JSGlobalObject*, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ };
+
+} // namespace JSC
+
+#endif // ErrorConstructor_h
diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.cpp b/Source/JavaScriptCore/runtime/ErrorInstance.cpp
new file mode 100644
index 000000000..91a6fc40e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ErrorInstance.cpp
@@ -0,0 +1,36 @@
+/*
+ * 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 {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(ErrorInstance);
+
+const ClassInfo ErrorInstance::s_info = { "Error", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(ErrorInstance) };
+
+ErrorInstance::ErrorInstance(JSGlobalData& globalData, Structure* structure)
+ : JSNonFinalObject(globalData, structure)
+ , m_appendSourceToMessage(false)
+{
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ErrorInstance.h b/Source/JavaScriptCore/runtime/ErrorInstance.h
new file mode 100644
index 000000000..888bfe856
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ErrorInstance.h
@@ -0,0 +1,75 @@
+/*
+ * 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 JSNonFinalObject {
+ public:
+ typedef JSNonFinalObject Base;
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), &s_info);
+ }
+
+ static ErrorInstance* create(JSGlobalData& globalData, Structure* structure, const UString& message)
+ {
+ ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(globalData.heap)) ErrorInstance(globalData, structure);
+ instance->finishCreation(globalData, message);
+ return instance;
+ }
+ static ErrorInstance* create(ExecState* exec, Structure* structure, JSValue message)
+ {
+ if (message.isUndefined()) {
+ ErrorInstance* instance = new (NotNull, allocateCell<ErrorInstance>(*exec->heap())) ErrorInstance(exec->globalData(), structure);
+ instance->finishCreation(exec->globalData(), UString());
+ return instance;
+ }
+ return create(exec->globalData(), structure, message.toString(exec));
+ }
+
+ bool appendSourceToMessage() { return m_appendSourceToMessage; }
+ void setAppendSourceToMessage() { m_appendSourceToMessage = true; }
+ void clearAppendSourceToMessage() { m_appendSourceToMessage = false; }
+
+ protected:
+ explicit ErrorInstance(JSGlobalData&, Structure*);
+
+ void finishCreation(JSGlobalData& globalData, const UString& message)
+ {
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+ if (!message.isNull())
+ putDirect(globalData, globalData.propertyNames->message, jsString(&globalData, message), DontEnum);
+ }
+
+ bool m_appendSourceToMessage;
+ };
+
+} // namespace JSC
+
+#endif // ErrorInstance_h
diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.cpp b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp
new file mode 100644
index 000000000..e1a395c0e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ErrorPrototype.cpp
@@ -0,0 +1,138 @@
+/*
+ * 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 "Error.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+#include "ObjectPrototype.h"
+#include "StringRecursionChecker.h"
+#include "UString.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype);
+
+static EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*);
+
+}
+
+#include "ErrorPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo ErrorPrototype::s_info = { "Error", &ErrorInstance::s_info, 0, ExecState::errorPrototypeTable, CREATE_METHOD_TABLE(ErrorPrototype) };
+
+/* Source for ErrorPrototype.lut.h
+@begin errorPrototypeTable
+ toString errorProtoFuncToString DontEnum|Function 0
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype);
+
+ErrorPrototype::ErrorPrototype(ExecState* exec, Structure* structure)
+ : ErrorInstance(exec->globalData(), structure)
+{
+}
+
+void ErrorPrototype::finishCreation(ExecState* exec, JSGlobalObject*)
+{
+ Base::finishCreation(exec->globalData(), "");
+ ASSERT(inherits(&s_info));
+ putDirect(exec->globalData(), exec->propertyNames().name, jsNontrivialString(exec, "Error"), DontEnum);
+}
+
+bool ErrorPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<ErrorInstance>(exec, ExecState::errorPrototypeTable(exec), jsCast<ErrorPrototype*>(cell), propertyName, slot);
+}
+
+bool ErrorPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<ErrorInstance>(exec, ExecState::errorPrototypeTable(exec), jsCast<ErrorPrototype*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Functions ---------------------------
+
+// ECMA-262 5.1, 15.11.4.4
+EncodedJSValue JSC_HOST_CALL errorProtoFuncToString(ExecState* exec)
+{
+ // 1. Let O be the this value.
+ JSValue thisValue = exec->hostThisValue();
+
+ // 2. If Type(O) is not Object, throw a TypeError exception.
+ if (!thisValue.isObject())
+ return throwVMTypeError(exec);
+ JSObject* thisObj = asObject(thisValue);
+
+ // Guard against recursion!
+ StringRecursionChecker checker(exec, thisObj);
+ if (JSValue earlyReturnValue = checker.earlyReturnValue())
+ return JSValue::encode(earlyReturnValue);
+
+ // 3. Let name be the result of calling the [[Get]] internal method of O with argument "name".
+ JSValue name = thisObj->get(exec, exec->propertyNames().name);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 4. If name is undefined, then let name be "Error"; else let name be ToString(name).
+ UString nameString;
+ if (name.isUndefined())
+ nameString = "Error";
+ else {
+ nameString = name.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+
+ // 5. Let msg be the result of calling the [[Get]] internal method of O with argument "message".
+ JSValue message = thisObj->get(exec, exec->propertyNames().message);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // (sic)
+ // 6. If msg is undefined, then let msg be the empty String; else let msg be ToString(msg).
+ // 7. If msg is undefined, then let msg be the empty String; else let msg be ToString(msg).
+ UString messageString;
+ if (message.isUndefined())
+ messageString = "";
+ else {
+ messageString = message.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+
+ // 8. If name is the empty String, return msg.
+ if (!nameString.length())
+ return JSValue::encode(message.isString() ? message : jsString(exec, messageString));
+
+ // 9. If msg is the empty String, return name.
+ if (!messageString.length())
+ return JSValue::encode(name.isString() ? name : jsNontrivialString(exec, nameString));
+
+ // 10. Return the result of concatenating name, ":", a single space character, and msg.
+ return JSValue::encode(jsMakeNontrivialString(exec, nameString, ": ", messageString));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ErrorPrototype.h b/Source/JavaScriptCore/runtime/ErrorPrototype.h
new file mode 100644
index 000000000..6f02583a6
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ErrorPrototype.h
@@ -0,0 +1,61 @@
+/*
+ * 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:
+ typedef ErrorInstance Base;
+
+ static ErrorPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ ErrorPrototype* prototype = new (NotNull, allocateCell<ErrorPrototype>(*exec->heap())) ErrorPrototype(exec, structure);
+ prototype->finishCreation(exec, globalObject);
+ return prototype;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ErrorInstanceType, StructureFlags), &s_info);
+ }
+
+ protected:
+ ErrorPrototype(ExecState*, Structure*);
+ void finishCreation(ExecState*, JSGlobalObject*);
+
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ErrorInstance::StructureFlags;
+
+ private:
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ };
+
+} // namespace JSC
+
+#endif // ErrorPrototype_h
diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
new file mode 100644
index 000000000..05e971f7f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.cpp
@@ -0,0 +1,170 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "ExceptionHelpers.h"
+
+#include "CodeBlock.h"
+#include "CallFrame.h"
+#include "ErrorInstance.h"
+#include "JSGlobalObjectFunctions.h"
+#include "JSObject.h"
+#include "JSNotAnObject.h"
+#include "Interpreter.h"
+#include "Nodes.h"
+#include "UStringConcatenate.h"
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(InterruptedExecutionError);
+
+const ClassInfo InterruptedExecutionError::s_info = { "InterruptedExecutionError", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(InterruptedExecutionError) };
+
+JSValue InterruptedExecutionError::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType hint)
+{
+ if (hint == PreferString)
+ return jsNontrivialString(exec, "JavaScript execution exceeded timeout.");
+ return JSValue(std::numeric_limits<double>::quiet_NaN());
+}
+
+JSObject* createInterruptedExecutionException(JSGlobalData* globalData)
+{
+ return InterruptedExecutionError::create(*globalData);
+}
+
+bool isInterruptedExecutionException(JSObject* object)
+{
+ return object->inherits(&InterruptedExecutionError::s_info);
+}
+
+bool isInterruptedExecutionException(JSValue value)
+{
+ return value.inherits(&InterruptedExecutionError::s_info);
+}
+
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(TerminatedExecutionError);
+
+const ClassInfo TerminatedExecutionError::s_info = { "TerminatedExecutionError", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(TerminatedExecutionError) };
+
+JSValue TerminatedExecutionError::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType hint)
+{
+ if (hint == PreferString)
+ return jsNontrivialString(exec, "JavaScript execution terminated.");
+ return JSValue(std::numeric_limits<double>::quiet_NaN());
+}
+
+JSObject* createTerminatedExecutionException(JSGlobalData* globalData)
+{
+ return TerminatedExecutionError::create(*globalData);
+}
+
+bool isTerminatedExecutionException(JSObject* object)
+{
+ return object->inherits(&TerminatedExecutionError::s_info);
+}
+
+bool isTerminatedExecutionException(JSValue value)
+{
+ return value.inherits(&TerminatedExecutionError::s_info);
+}
+
+
+JSObject* createStackOverflowError(ExecState* exec)
+{
+ return createRangeError(exec, "Maximum call stack size exceeded.");
+}
+
+JSObject* createStackOverflowError(JSGlobalObject* globalObject)
+{
+ return createRangeError(globalObject, "Maximum call stack size exceeded.");
+}
+
+JSObject* createUndefinedVariableError(ExecState* exec, const Identifier& ident)
+{
+ UString message(makeUString("Can't find variable: ", ident.ustring()));
+ return createReferenceError(exec, message);
+}
+
+JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value)
+{
+ UString errorMessage = makeUString("'", value.toString(exec), "' is not a valid argument for '", op, "'");
+ JSObject* exception = createTypeError(exec, errorMessage);
+ ASSERT(exception->isErrorInstance());
+ static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage();
+ return exception;
+}
+
+JSObject* createNotAConstructorError(ExecState* exec, JSValue value)
+{
+ UString errorMessage = makeUString("'", value.toString(exec), "' is not a constructor");
+ JSObject* exception = createTypeError(exec, errorMessage);
+ ASSERT(exception->isErrorInstance());
+ static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage();
+ return exception;
+}
+
+JSObject* createNotAFunctionError(ExecState* exec, JSValue value)
+{
+ UString errorMessage = makeUString("'", value.toString(exec), "' is not a function");
+ JSObject* exception = createTypeError(exec, errorMessage);
+ ASSERT(exception->isErrorInstance());
+ static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage();
+ return exception;
+}
+
+JSObject* createNotAnObjectError(ExecState* exec, JSValue value)
+{
+ UString errorMessage = makeUString("'", value.toString(exec), "' is not an object");
+ JSObject* exception = createTypeError(exec, errorMessage);
+ ASSERT(exception->isErrorInstance());
+ static_cast<ErrorInstance*>(exception)->setAppendSourceToMessage();
+ return exception;
+}
+
+JSObject* createErrorForInvalidGlobalAssignment(ExecState* exec, const UString& propertyName)
+{
+ return createReferenceError(exec, makeUString("Strict mode forbids implicit creation of global property '", propertyName, "'"));
+}
+
+JSObject* createOutOfMemoryError(JSGlobalObject* globalObject)
+{
+ return createError(globalObject, "Out of memory");
+}
+
+JSObject* throwOutOfMemoryError(ExecState* exec)
+{
+ return throwError(exec, createOutOfMemoryError(exec->lexicalGlobalObject()));
+}
+
+JSObject* throwStackOverflowError(ExecState* exec)
+{
+ return throwError(exec, createStackOverflowError(exec));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ExceptionHelpers.h b/Source/JavaScriptCore/runtime/ExceptionHelpers.h
new file mode 100644
index 000000000..f71d1a308
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ExceptionHelpers.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ExceptionHelpers_h
+#define ExceptionHelpers_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+JSObject* createInterruptedExecutionException(JSGlobalData*);
+bool isInterruptedExecutionException(JSObject*);
+bool isInterruptedExecutionException(JSValue);
+
+JSObject* createTerminatedExecutionException(JSGlobalData*);
+bool isTerminatedExecutionException(JSObject*);
+bool isTerminatedExecutionException(JSValue);
+
+JSObject* createStackOverflowError(ExecState*);
+JSObject* createStackOverflowError(JSGlobalObject*);
+JSObject* createOutOfMemoryError(JSGlobalObject*);
+JSObject* createUndefinedVariableError(ExecState*, const Identifier&);
+JSObject* createNotAnObjectError(ExecState*, JSValue);
+JSObject* createInvalidParamError(ExecState*, const char* op, JSValue);
+JSObject* createNotAConstructorError(ExecState*, JSValue);
+JSObject* createNotAFunctionError(ExecState*, JSValue);
+JSObject* createErrorForInvalidGlobalAssignment(ExecState*, const UString&);
+
+JSObject* throwOutOfMemoryError(ExecState*);
+JSObject* throwStackOverflowError(ExecState*);
+
+
+class InterruptedExecutionError : public JSNonFinalObject {
+private:
+ InterruptedExecutionError(JSGlobalData& globalData)
+ : JSNonFinalObject(globalData, globalData.interruptedExecutionErrorStructure.get())
+ {
+ }
+
+ static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
+
+public:
+ typedef JSNonFinalObject Base;
+
+ static InterruptedExecutionError* create(JSGlobalData& globalData)
+ {
+ InterruptedExecutionError* error = new (NotNull, allocateCell<InterruptedExecutionError>(globalData.heap)) InterruptedExecutionError(globalData);
+ error->finishCreation(globalData);
+ return error;
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+};
+
+class TerminatedExecutionError : public JSNonFinalObject {
+private:
+ TerminatedExecutionError(JSGlobalData& globalData)
+ : JSNonFinalObject(globalData, globalData.terminatedExecutionErrorStructure.get())
+ {
+ }
+
+ static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
+
+public:
+ typedef JSNonFinalObject Base;
+
+ static TerminatedExecutionError* create(JSGlobalData& globalData)
+ {
+ TerminatedExecutionError* error = new (NotNull, allocateCell<TerminatedExecutionError>(globalData.heap)) TerminatedExecutionError(globalData);
+ error->finishCreation(globalData);
+ return error;
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+};
+
+} // namespace JSC
+
+#endif // ExceptionHelpers_h
diff --git a/Source/JavaScriptCore/runtime/Executable.cpp b/Source/JavaScriptCore/runtime/Executable.cpp
new file mode 100644
index 000000000..ad86463db
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Executable.cpp
@@ -0,0 +1,756 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED 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 "Executable.h"
+
+#include "BytecodeGenerator.h"
+#include "CodeBlock.h"
+#include "DFGDriver.h"
+#include "JIT.h"
+#include "Parser.h"
+#include "UStringBuilder.h"
+#include "Vector.h"
+
+namespace JSC {
+
+const ClassInfo ExecutableBase::s_info = { "Executable", 0, 0, 0, CREATE_METHOD_TABLE(ExecutableBase) };
+
+void ExecutableBase::destroy(JSCell* cell)
+{
+ jsCast<ExecutableBase*>(cell)->ExecutableBase::~ExecutableBase();
+}
+
+inline void ExecutableBase::clearCode()
+{
+#if ENABLE(JIT)
+ m_jitCodeForCall.clear();
+ m_jitCodeForConstruct.clear();
+ m_jitCodeForCallWithArityCheck = MacroAssemblerCodePtr();
+ m_jitCodeForConstructWithArityCheck = MacroAssemblerCodePtr();
+#endif
+ m_numParametersForCall = NUM_PARAMETERS_NOT_COMPILED;
+ m_numParametersForConstruct = NUM_PARAMETERS_NOT_COMPILED;
+}
+
+#if ENABLE(DFG_JIT)
+Intrinsic ExecutableBase::intrinsic() const
+{
+ if (const NativeExecutable* nativeExecutable = jsDynamicCast<const NativeExecutable*>(this))
+ return nativeExecutable->intrinsic();
+ return NoIntrinsic;
+}
+#endif
+
+const ClassInfo NativeExecutable::s_info = { "NativeExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(NativeExecutable) };
+
+void NativeExecutable::destroy(JSCell* cell)
+{
+ jsCast<NativeExecutable*>(cell)->NativeExecutable::~NativeExecutable();
+}
+
+#if ENABLE(DFG_JIT)
+Intrinsic NativeExecutable::intrinsic() const
+{
+ return m_intrinsic;
+}
+#endif
+
+#if ENABLE(JIT)
+// Utility method used for jettisoning code blocks.
+template<typename T>
+static void jettisonCodeBlock(JSGlobalData& globalData, OwnPtr<T>& codeBlock)
+{
+ ASSERT(codeBlock->getJITType() != JITCode::BaselineJIT);
+ ASSERT(codeBlock->alternative());
+ OwnPtr<T> codeBlockToJettison = codeBlock.release();
+ codeBlock = static_pointer_cast<T>(codeBlockToJettison->releaseAlternative());
+ codeBlockToJettison->unlinkIncomingCalls();
+ globalData.heap.jettisonDFGCodeBlock(static_pointer_cast<CodeBlock>(codeBlockToJettison.release()));
+}
+#endif
+
+void NativeExecutable::finalize(JSCell* cell)
+{
+ jsCast<NativeExecutable*>(cell)->clearCode();
+}
+
+const ClassInfo ScriptExecutable::s_info = { "ScriptExecutable", &ExecutableBase::s_info, 0, 0, CREATE_METHOD_TABLE(ScriptExecutable) };
+
+void ScriptExecutable::destroy(JSCell* cell)
+{
+ jsCast<ScriptExecutable*>(cell)->ScriptExecutable::~ScriptExecutable();
+}
+
+const ClassInfo EvalExecutable::s_info = { "EvalExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(EvalExecutable) };
+
+EvalExecutable::EvalExecutable(ExecState* exec, const SourceCode& source, bool inStrictContext)
+ : ScriptExecutable(exec->globalData().evalExecutableStructure.get(), exec, source, inStrictContext)
+{
+}
+
+void EvalExecutable::destroy(JSCell* cell)
+{
+ jsCast<EvalExecutable*>(cell)->EvalExecutable::~EvalExecutable();
+}
+
+const ClassInfo ProgramExecutable::s_info = { "ProgramExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(ProgramExecutable) };
+
+ProgramExecutable::ProgramExecutable(ExecState* exec, const SourceCode& source)
+ : ScriptExecutable(exec->globalData().programExecutableStructure.get(), exec, source, false)
+{
+}
+
+void ProgramExecutable::destroy(JSCell* cell)
+{
+ jsCast<ProgramExecutable*>(cell)->ProgramExecutable::~ProgramExecutable();
+}
+
+const ClassInfo FunctionExecutable::s_info = { "FunctionExecutable", &ScriptExecutable::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionExecutable) };
+
+FunctionExecutable::FunctionExecutable(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext)
+ : ScriptExecutable(globalData.functionExecutableStructure.get(), globalData, source, inStrictContext)
+ , m_numCapturedVariables(0)
+ , m_forceUsesArguments(forceUsesArguments)
+ , m_parameters(parameters)
+ , m_name(name)
+ , m_symbolTable(0)
+{
+}
+
+FunctionExecutable::FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool inStrictContext)
+ : ScriptExecutable(exec->globalData().functionExecutableStructure.get(), exec, source, inStrictContext)
+ , m_numCapturedVariables(0)
+ , m_forceUsesArguments(forceUsesArguments)
+ , m_parameters(parameters)
+ , m_name(name)
+ , m_symbolTable(0)
+{
+}
+
+void FunctionExecutable::destroy(JSCell* cell)
+{
+ jsCast<FunctionExecutable*>(cell)->FunctionExecutable::~FunctionExecutable();
+}
+
+JSObject* EvalExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
+{
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ ASSERT(!!m_evalCodeBlock);
+ JSObject* error = 0;
+ if (m_evalCodeBlock->getJITType() != JITCode::topTierJIT())
+ error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_evalCodeBlock->getJITType()));
+ ASSERT(!!m_evalCodeBlock);
+ return error;
+}
+
+JSObject* EvalExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType)
+{
+ SamplingRegion samplingRegion(jitType == JITCode::BaselineJIT ? "Baseline Compilation (TOTAL)" : "DFG Compilation (TOTAL)");
+
+#if !ENABLE(JIT)
+ UNUSED_PARAM(jitType);
+#endif
+ JSObject* exception = 0;
+ JSGlobalData* globalData = &exec->globalData();
+ JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
+
+ if (!!m_evalCodeBlock && m_evalCodeBlock->canProduceCopyWithBytecode()) {
+ BytecodeDestructionBlocker blocker(m_evalCodeBlock.get());
+ OwnPtr<EvalCodeBlock> newCodeBlock = adoptPtr(new EvalCodeBlock(CodeBlock::CopyParsedBlock, *m_evalCodeBlock));
+ newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_evalCodeBlock.release()));
+ m_evalCodeBlock = newCodeBlock.release();
+ } else {
+ if (!lexicalGlobalObject->evalEnabled())
+ return throwError(exec, createEvalError(exec, "Eval is disabled"));
+ RefPtr<EvalNode> evalNode = parse<EvalNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, EvalNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
+ if (!evalNode) {
+ ASSERT(exception);
+ return exception;
+ }
+ recordParse(evalNode->features(), evalNode->hasCapturedVariables(), evalNode->lineNo(), evalNode->lastLine());
+
+ JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
+
+ OwnPtr<CodeBlock> previousCodeBlock = m_evalCodeBlock.release();
+ ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock);
+ m_evalCodeBlock = adoptPtr(new EvalCodeBlock(this, globalObject, source().provider(), scopeChainNode->localDepth(), previousCodeBlock.release()));
+ OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(evalNode.get(), scopeChainNode, m_evalCodeBlock->symbolTable(), m_evalCodeBlock.get(), !!m_evalCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation)));
+ if ((exception = generator->generate())) {
+ m_evalCodeBlock = static_pointer_cast<EvalCodeBlock>(m_evalCodeBlock->releaseAlternative());
+ evalNode->destroyData();
+ return exception;
+ }
+
+ evalNode->destroyData();
+ m_evalCodeBlock->copyPostParseDataFromAlternative();
+ }
+
+#if ENABLE(JIT)
+ if (exec->globalData().canUseJIT()) {
+ bool dfgCompiled = false;
+ if (jitType == JITCode::DFGJIT)
+ dfgCompiled = DFG::tryCompile(exec, m_evalCodeBlock.get(), m_jitCodeForCall);
+ if (dfgCompiled)
+ ASSERT(!m_evalCodeBlock->alternative() || !m_evalCodeBlock->alternative()->hasIncomingCalls());
+ else {
+ if (m_evalCodeBlock->alternative()) {
+ // There is already an alternative piece of code compiled with a different
+ // JIT, so we can silently fail.
+ m_evalCodeBlock = static_pointer_cast<EvalCodeBlock>(m_evalCodeBlock->releaseAlternative());
+ return 0;
+ }
+ m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_evalCodeBlock.get());
+ }
+#if !ENABLE(OPCODE_SAMPLING)
+ if (!BytecodeGenerator::dumpsGeneratedCode())
+ m_evalCodeBlock->handleBytecodeDiscardingOpportunity();
+#endif
+ m_evalCodeBlock->setJITCode(m_jitCodeForCall, MacroAssemblerCodePtr());
+ }
+#endif
+
+#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
+ if (!m_jitCodeForCall)
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock));
+ else
+#endif
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock) + m_jitCodeForCall.size());
+#else
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_evalCodeBlock));
+#endif
+
+ return 0;
+}
+
+#if ENABLE(JIT)
+void EvalExecutable::jettisonOptimizedCode(JSGlobalData& globalData)
+{
+ jettisonCodeBlock(globalData, m_evalCodeBlock);
+ m_jitCodeForCall = m_evalCodeBlock->getJITCode();
+ ASSERT(!m_jitCodeForCallWithArityCheck);
+}
+#endif
+
+void EvalExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ EvalExecutable* thisObject = jsCast<EvalExecutable*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ ScriptExecutable::visitChildren(thisObject, visitor);
+ if (thisObject->m_evalCodeBlock)
+ thisObject->m_evalCodeBlock->visitAggregate(visitor);
+}
+
+void EvalExecutable::unlinkCalls()
+{
+#if ENABLE(JIT)
+ if (!m_jitCodeForCall)
+ return;
+ ASSERT(m_evalCodeBlock);
+ m_evalCodeBlock->unlinkCalls();
+#endif
+}
+
+void EvalExecutable::finalize(JSCell* cell)
+{
+ jsCast<EvalExecutable*>(cell)->clearCode();
+}
+
+inline void EvalExecutable::clearCode()
+{
+ if (m_evalCodeBlock) {
+ m_evalCodeBlock->clearEvalCache();
+ m_evalCodeBlock.clear();
+ }
+ Base::clearCode();
+}
+
+JSObject* ProgramExecutable::checkSyntax(ExecState* exec)
+{
+ JSObject* exception = 0;
+ JSGlobalData* globalData = &exec->globalData();
+ JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
+ RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
+ if (programNode)
+ return 0;
+ ASSERT(exception);
+ return exception;
+}
+
+JSObject* ProgramExecutable::compileOptimized(ExecState* exec, ScopeChainNode* scopeChainNode)
+{
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ ASSERT(!!m_programCodeBlock);
+ JSObject* error = 0;
+ if (m_programCodeBlock->getJITType() != JITCode::topTierJIT())
+ error = compileInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_programCodeBlock->getJITType()));
+ ASSERT(!!m_programCodeBlock);
+ return error;
+}
+
+JSObject* ProgramExecutable::compileInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType)
+{
+ SamplingRegion samplingRegion(jitType == JITCode::BaselineJIT ? "Baseline Compilation (TOTAL)" : "DFG Compilation (TOTAL)");
+
+#if !ENABLE(JIT)
+ UNUSED_PARAM(jitType);
+#endif
+ JSObject* exception = 0;
+ JSGlobalData* globalData = &exec->globalData();
+ JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
+
+ if (!!m_programCodeBlock && m_programCodeBlock->canProduceCopyWithBytecode()) {
+ BytecodeDestructionBlocker blocker(m_programCodeBlock.get());
+ OwnPtr<ProgramCodeBlock> newCodeBlock = adoptPtr(new ProgramCodeBlock(CodeBlock::CopyParsedBlock, *m_programCodeBlock));
+ newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_programCodeBlock.release()));
+ m_programCodeBlock = newCodeBlock.release();
+ } else {
+ RefPtr<ProgramNode> programNode = parse<ProgramNode>(globalData, lexicalGlobalObject, m_source, 0, isStrictMode() ? JSParseStrict : JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, lexicalGlobalObject->debugger(), exec, &exception);
+ if (!programNode) {
+ ASSERT(exception);
+ return exception;
+ }
+ recordParse(programNode->features(), programNode->hasCapturedVariables(), programNode->lineNo(), programNode->lastLine());
+
+ JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
+
+ OwnPtr<CodeBlock> previousCodeBlock = m_programCodeBlock.release();
+ ASSERT((jitType == JITCode::bottomTierJIT()) == !previousCodeBlock);
+ m_programCodeBlock = adoptPtr(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider(), previousCodeBlock.release()));
+ OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(programNode.get(), scopeChainNode, &globalObject->symbolTable(), m_programCodeBlock.get(), !!m_programCodeBlock->alternative() ? OptimizingCompilation : FirstCompilation)));
+ if ((exception = generator->generate())) {
+ m_programCodeBlock = static_pointer_cast<ProgramCodeBlock>(m_programCodeBlock->releaseAlternative());
+ programNode->destroyData();
+ return exception;
+ }
+
+ programNode->destroyData();
+ m_programCodeBlock->copyPostParseDataFromAlternative();
+ }
+
+#if ENABLE(JIT)
+ if (exec->globalData().canUseJIT()) {
+ bool dfgCompiled = false;
+ if (jitType == JITCode::DFGJIT)
+ dfgCompiled = DFG::tryCompile(exec, m_programCodeBlock.get(), m_jitCodeForCall);
+ if (dfgCompiled) {
+ if (m_programCodeBlock->alternative())
+ m_programCodeBlock->alternative()->unlinkIncomingCalls();
+ } else {
+ if (m_programCodeBlock->alternative()) {
+ m_programCodeBlock = static_pointer_cast<ProgramCodeBlock>(m_programCodeBlock->releaseAlternative());
+ return 0;
+ }
+ m_jitCodeForCall = JIT::compile(scopeChainNode->globalData, m_programCodeBlock.get());
+ }
+#if !ENABLE(OPCODE_SAMPLING)
+ if (!BytecodeGenerator::dumpsGeneratedCode())
+ m_programCodeBlock->handleBytecodeDiscardingOpportunity();
+#endif
+ m_programCodeBlock->setJITCode(m_jitCodeForCall, MacroAssemblerCodePtr());
+ }
+#endif
+
+#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
+ if (!m_jitCodeForCall)
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock));
+ else
+#endif
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock) + m_jitCodeForCall.size());
+#else
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_programCodeBlock));
+#endif
+
+ return 0;
+}
+
+#if ENABLE(JIT)
+void ProgramExecutable::jettisonOptimizedCode(JSGlobalData& globalData)
+{
+ jettisonCodeBlock(globalData, m_programCodeBlock);
+ m_jitCodeForCall = m_programCodeBlock->getJITCode();
+ ASSERT(!m_jitCodeForCallWithArityCheck);
+}
+#endif
+
+void ProgramExecutable::unlinkCalls()
+{
+#if ENABLE(JIT)
+ if (!m_jitCodeForCall)
+ return;
+ ASSERT(m_programCodeBlock);
+ m_programCodeBlock->unlinkCalls();
+#endif
+}
+
+void ProgramExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ ProgramExecutable* thisObject = jsCast<ProgramExecutable*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ ScriptExecutable::visitChildren(thisObject, visitor);
+ if (thisObject->m_programCodeBlock)
+ thisObject->m_programCodeBlock->visitAggregate(visitor);
+}
+
+void ProgramExecutable::finalize(JSCell* cell)
+{
+ jsCast<ProgramExecutable*>(cell)->clearCode();
+}
+
+inline void ProgramExecutable::clearCode()
+{
+ if (m_programCodeBlock) {
+ m_programCodeBlock->clearEvalCache();
+ m_programCodeBlock.clear();
+ }
+ Base::clearCode();
+}
+
+FunctionCodeBlock* FunctionExecutable::baselineCodeBlockFor(CodeSpecializationKind kind)
+{
+ FunctionCodeBlock* result;
+ if (kind == CodeForCall)
+ result = m_codeBlockForCall.get();
+ else {
+ ASSERT(kind == CodeForConstruct);
+ result = m_codeBlockForConstruct.get();
+ }
+ if (!result)
+ return 0;
+ while (result->alternative())
+ result = static_cast<FunctionCodeBlock*>(result->alternative());
+ ASSERT(result);
+ ASSERT(result->getJITType() == JITCode::BaselineJIT);
+ return result;
+}
+
+JSObject* FunctionExecutable::compileOptimizedForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
+{
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ ASSERT(!!m_codeBlockForCall);
+ JSObject* error = 0;
+ if (m_codeBlockForCall->getJITType() != JITCode::topTierJIT())
+ error = compileForCallInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForCall->getJITType()));
+ ASSERT(!!m_codeBlockForCall);
+ return error;
+}
+
+JSObject* FunctionExecutable::compileOptimizedForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
+{
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ ASSERT(!!m_codeBlockForConstruct);
+ JSObject* error = 0;
+ if (m_codeBlockForConstruct->getJITType() != JITCode::topTierJIT())
+ error = compileForConstructInternal(exec, scopeChainNode, JITCode::nextTierJIT(m_codeBlockForConstruct->getJITType()));
+ ASSERT(!!m_codeBlockForConstruct);
+ return error;
+}
+
+FunctionCodeBlock* FunctionExecutable::codeBlockWithBytecodeFor(CodeSpecializationKind kind)
+{
+ FunctionCodeBlock* codeBlock = baselineCodeBlockFor(kind);
+ if (codeBlock->canProduceCopyWithBytecode())
+ return codeBlock;
+ return 0;
+}
+
+PassOwnPtr<FunctionCodeBlock> FunctionExecutable::produceCodeBlockFor(ScopeChainNode* scopeChainNode, CompilationKind compilationKind, CodeSpecializationKind specializationKind, JSObject*& exception)
+{
+ if (!!codeBlockFor(specializationKind) && codeBlockFor(specializationKind)->canProduceCopyWithBytecode()) {
+ BytecodeDestructionBlocker blocker(codeBlockFor(specializationKind).get());
+ return adoptPtr(new FunctionCodeBlock(CodeBlock::CopyParsedBlock, *codeBlockFor(specializationKind)));
+ }
+
+ exception = 0;
+ JSGlobalData* globalData = scopeChainNode->globalData;
+ JSGlobalObject* globalObject = scopeChainNode->globalObject.get();
+ RefPtr<FunctionBodyNode> body = parse<FunctionBodyNode>(globalData, globalObject, m_source, m_parameters.get(), isStrictMode() ? JSParseStrict : JSParseNormal, FunctionBodyNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, 0, 0, &exception);
+
+ if (!body) {
+ ASSERT(exception);
+ return nullptr;
+ }
+ if (m_forceUsesArguments)
+ body->setUsesArguments();
+ body->finishParsing(m_parameters, m_name);
+ recordParse(body->features(), body->hasCapturedVariables(), body->lineNo(), body->lastLine());
+
+ OwnPtr<FunctionCodeBlock> result;
+ ASSERT((compilationKind == FirstCompilation) == !codeBlockFor(specializationKind));
+ result = adoptPtr(new FunctionCodeBlock(this, FunctionCode, globalObject, source().provider(), source().startOffset(), specializationKind == CodeForConstruct));
+ OwnPtr<BytecodeGenerator> generator(adoptPtr(new BytecodeGenerator(body.get(), scopeChainNode, result->symbolTable(), result.get(), compilationKind)));
+ exception = generator->generate();
+ body->destroyData();
+ if (exception)
+ return nullptr;
+
+ result->copyPostParseDataFrom(codeBlockFor(specializationKind).get());
+ return result.release();
+}
+
+JSObject* FunctionExecutable::compileForCallInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType)
+{
+ SamplingRegion samplingRegion(jitType == JITCode::BaselineJIT ? "Baseline Compilation (TOTAL)" : "DFG Compilation (TOTAL)");
+
+#if !ENABLE(JIT)
+ UNUSED_PARAM(exec);
+ UNUSED_PARAM(jitType);
+ UNUSED_PARAM(exec);
+#endif
+ ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForCall);
+ JSObject* exception;
+ OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scopeChainNode, !!m_codeBlockForCall ? OptimizingCompilation : FirstCompilation, CodeForCall, exception);
+ if (!newCodeBlock)
+ return exception;
+
+ newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_codeBlockForCall.release()));
+ m_codeBlockForCall = newCodeBlock.release();
+
+ m_numParametersForCall = m_codeBlockForCall->m_numParameters;
+ ASSERT(m_numParametersForCall);
+ m_numCapturedVariables = m_codeBlockForCall->m_numCapturedVars;
+ m_symbolTable = m_codeBlockForCall->sharedSymbolTable();
+
+#if ENABLE(JIT)
+ JSGlobalData* globalData = scopeChainNode->globalData;
+ if (globalData->canUseJIT()) {
+ bool dfgCompiled = false;
+ if (jitType == JITCode::DFGJIT)
+ dfgCompiled = DFG::tryCompileFunction(exec, m_codeBlockForCall.get(), m_jitCodeForCall, m_jitCodeForCallWithArityCheck);
+ if (dfgCompiled) {
+ if (m_codeBlockForCall->alternative())
+ m_codeBlockForCall->alternative()->unlinkIncomingCalls();
+ } else {
+ if (m_codeBlockForCall->alternative()) {
+ m_codeBlockForCall = static_pointer_cast<FunctionCodeBlock>(m_codeBlockForCall->releaseAlternative());
+ m_symbolTable = m_codeBlockForCall->sharedSymbolTable();
+ return 0;
+ }
+ m_jitCodeForCall = JIT::compile(globalData, m_codeBlockForCall.get(), &m_jitCodeForCallWithArityCheck);
+ }
+#if !ENABLE(OPCODE_SAMPLING)
+ if (!BytecodeGenerator::dumpsGeneratedCode())
+ m_codeBlockForCall->handleBytecodeDiscardingOpportunity();
+#endif
+
+ m_codeBlockForCall->setJITCode(m_jitCodeForCall, m_jitCodeForCallWithArityCheck);
+ }
+#endif
+
+#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
+ if (!m_jitCodeForCall)
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall));
+ else
+#endif
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall) + m_jitCodeForCall.size());
+#else
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForCall));
+#endif
+
+ return 0;
+}
+
+JSObject* FunctionExecutable::compileForConstructInternal(ExecState* exec, ScopeChainNode* scopeChainNode, JITCode::JITType jitType)
+{
+ SamplingRegion samplingRegion(jitType == JITCode::BaselineJIT ? "Baseline Compilation (TOTAL)" : "DFG Compilation (TOTAL)");
+
+#if !ENABLE(JIT)
+ UNUSED_PARAM(jitType);
+ UNUSED_PARAM(exec);
+#endif
+
+ ASSERT((jitType == JITCode::bottomTierJIT()) == !m_codeBlockForConstruct);
+ JSObject* exception;
+ OwnPtr<FunctionCodeBlock> newCodeBlock = produceCodeBlockFor(scopeChainNode, !!m_codeBlockForConstruct ? OptimizingCompilation : FirstCompilation, CodeForConstruct, exception);
+ if (!newCodeBlock)
+ return exception;
+
+ newCodeBlock->setAlternative(static_pointer_cast<CodeBlock>(m_codeBlockForConstruct.release()));
+ m_codeBlockForConstruct = newCodeBlock.release();
+
+ m_numParametersForConstruct = m_codeBlockForConstruct->m_numParameters;
+ ASSERT(m_numParametersForConstruct);
+ m_numCapturedVariables = m_codeBlockForConstruct->m_numCapturedVars;
+ m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable();
+
+#if ENABLE(JIT)
+ JSGlobalData* globalData = scopeChainNode->globalData;
+ if (globalData->canUseJIT()) {
+ bool dfgCompiled = false;
+ if (jitType == JITCode::DFGJIT)
+ dfgCompiled = DFG::tryCompileFunction(exec, m_codeBlockForConstruct.get(), m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck);
+ if (dfgCompiled) {
+ if (m_codeBlockForConstruct->alternative())
+ m_codeBlockForConstruct->alternative()->unlinkIncomingCalls();
+ } else {
+ if (m_codeBlockForConstruct->alternative()) {
+ m_codeBlockForConstruct = static_pointer_cast<FunctionCodeBlock>(m_codeBlockForConstruct->releaseAlternative());
+ m_symbolTable = m_codeBlockForConstruct->sharedSymbolTable();
+ return 0;
+ }
+ m_jitCodeForConstruct = JIT::compile(globalData, m_codeBlockForConstruct.get(), &m_jitCodeForConstructWithArityCheck);
+ }
+#if !ENABLE(OPCODE_SAMPLING)
+ if (!BytecodeGenerator::dumpsGeneratedCode())
+ m_codeBlockForConstruct->handleBytecodeDiscardingOpportunity();
+#endif
+
+ m_codeBlockForConstruct->setJITCode(m_jitCodeForConstruct, m_jitCodeForConstructWithArityCheck);
+ }
+#endif
+
+#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
+ if (!m_jitCodeForConstruct)
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct));
+ else
+#endif
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct) + m_jitCodeForConstruct.size());
+#else
+ Heap::heap(this)->reportExtraMemoryCost(sizeof(*m_codeBlockForConstruct));
+#endif
+
+ return 0;
+}
+
+#if ENABLE(JIT)
+void FunctionExecutable::jettisonOptimizedCodeForCall(JSGlobalData& globalData)
+{
+ jettisonCodeBlock(globalData, m_codeBlockForCall);
+ m_jitCodeForCall = m_codeBlockForCall->getJITCode();
+ m_jitCodeForCallWithArityCheck = m_codeBlockForCall->getJITCodeWithArityCheck();
+}
+
+void FunctionExecutable::jettisonOptimizedCodeForConstruct(JSGlobalData& globalData)
+{
+ jettisonCodeBlock(globalData, m_codeBlockForConstruct);
+ m_jitCodeForConstruct = m_codeBlockForConstruct->getJITCode();
+ m_jitCodeForConstructWithArityCheck = m_codeBlockForConstruct->getJITCodeWithArityCheck();
+}
+#endif
+
+void FunctionExecutable::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ FunctionExecutable* thisObject = jsCast<FunctionExecutable*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ ScriptExecutable::visitChildren(thisObject, visitor);
+ if (thisObject->m_nameValue)
+ visitor.append(&thisObject->m_nameValue);
+ if (thisObject->m_codeBlockForCall)
+ thisObject->m_codeBlockForCall->visitAggregate(visitor);
+ if (thisObject->m_codeBlockForConstruct)
+ thisObject->m_codeBlockForConstruct->visitAggregate(visitor);
+}
+
+void FunctionExecutable::discardCode()
+{
+#if ENABLE(JIT)
+ // These first two checks are to handle the rare case where
+ // we are trying to evict code for a function during its
+ // codegen.
+ if (!m_jitCodeForCall && m_codeBlockForCall)
+ return;
+ if (!m_jitCodeForConstruct && m_codeBlockForConstruct)
+ return;
+#endif
+ clearCode();
+}
+
+void FunctionExecutable::finalize(JSCell* cell)
+{
+ jsCast<FunctionExecutable*>(cell)->clearCode();
+}
+
+inline void FunctionExecutable::clearCode()
+{
+ if (m_codeBlockForCall) {
+ m_codeBlockForCall->clearEvalCache();
+ m_codeBlockForCall.clear();
+ }
+ if (m_codeBlockForConstruct) {
+ m_codeBlockForConstruct->clearEvalCache();
+ m_codeBlockForConstruct.clear();
+ }
+ Base::clearCode();
+}
+
+void FunctionExecutable::unlinkCalls()
+{
+#if ENABLE(JIT)
+ if (!!m_jitCodeForCall) {
+ ASSERT(m_codeBlockForCall);
+ m_codeBlockForCall->unlinkCalls();
+ }
+ if (!!m_jitCodeForConstruct) {
+ ASSERT(m_codeBlockForConstruct);
+ m_codeBlockForConstruct->unlinkCalls();
+ }
+#endif
+}
+
+FunctionExecutable* FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, JSObject** exception)
+{
+ JSGlobalObject* lexicalGlobalObject = exec->lexicalGlobalObject();
+ RefPtr<ProgramNode> program = parse<ProgramNode>(&exec->globalData(), lexicalGlobalObject, source, 0, JSParseNormal, ProgramNode::isFunctionNode ? JSParseFunctionCode : JSParseProgramCode, debugger, exec, exception);
+ if (!program) {
+ ASSERT(*exception);
+ return 0;
+ }
+
+ // Uses of this function that would not result in a single function expression are invalid.
+ StatementNode* exprStatement = program->singleStatement();
+ ASSERT(exprStatement);
+ ASSERT(exprStatement->isExprStatement());
+ ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr();
+ ASSERT(funcExpr);
+ ASSERT(funcExpr->isFuncExprNode());
+ FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body();
+ ASSERT(body);
+
+ return FunctionExecutable::create(exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->isStrictMode(), body->lineNo(), body->lastLine());
+}
+
+UString FunctionExecutable::paramString() const
+{
+ FunctionParameters& parameters = *m_parameters;
+ UStringBuilder builder;
+ for (size_t pos = 0; pos < parameters.size(); ++pos) {
+ if (!builder.isEmpty())
+ builder.append(", ");
+ builder.append(parameters[pos].ustring());
+ }
+ return builder.toUString();
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/Executable.h b/Source/JavaScriptCore/runtime/Executable.h
new file mode 100644
index 000000000..cc44d61a7
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Executable.h
@@ -0,0 +1,716 @@
+/*
+ * Copyright (C) 2009, 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED 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 Executable_h
+#define Executable_h
+
+#include "CallData.h"
+#include "JSFunction.h"
+#include "Interpreter.h"
+#include "Nodes.h"
+#include "SamplingTool.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace JSC {
+
+ class CodeBlock;
+ class Debugger;
+ class EvalCodeBlock;
+ class FunctionCodeBlock;
+ class ProgramCodeBlock;
+ class ScopeChainNode;
+
+ struct ExceptionInfo;
+
+ enum CodeSpecializationKind { CodeForCall, CodeForConstruct };
+ enum CompilationKind { FirstCompilation, OptimizingCompilation };
+
+ inline bool isCall(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return true;
+ ASSERT(kind == CodeForConstruct);
+ return false;
+ }
+
+ class ExecutableBase : public JSCell {
+ friend class JIT;
+
+ protected:
+ static const int NUM_PARAMETERS_IS_HOST = 0;
+ static const int NUM_PARAMETERS_NOT_COMPILED = -1;
+
+ ExecutableBase(JSGlobalData& globalData, Structure* structure, int numParameters)
+ : JSCell(globalData, structure)
+ , m_numParametersForCall(numParameters)
+ , m_numParametersForConstruct(numParameters)
+ {
+ }
+
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData);
+ }
+
+ public:
+ typedef JSCell Base;
+
+ static void destroy(JSCell*);
+
+ bool isHostFunction() const
+ {
+ ASSERT((m_numParametersForCall == NUM_PARAMETERS_IS_HOST) == (m_numParametersForConstruct == NUM_PARAMETERS_IS_HOST));
+ return m_numParametersForCall == NUM_PARAMETERS_IS_HOST;
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); }
+
+ static const ClassInfo s_info;
+
+ protected:
+ static const unsigned StructureFlags = 0;
+ int m_numParametersForCall;
+ int m_numParametersForConstruct;
+
+#if ENABLE(JIT)
+ public:
+ JITCode& generatedJITCodeForCall()
+ {
+ ASSERT(m_jitCodeForCall);
+ return m_jitCodeForCall;
+ }
+
+ JITCode& generatedJITCodeForConstruct()
+ {
+ ASSERT(m_jitCodeForConstruct);
+ return m_jitCodeForConstruct;
+ }
+
+ JITCode& generatedJITCodeFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return generatedJITCodeForCall();
+ ASSERT(kind == CodeForConstruct);
+ return generatedJITCodeForConstruct();
+ }
+
+ MacroAssemblerCodePtr generatedJITCodeForCallWithArityCheck()
+ {
+ ASSERT(m_jitCodeForCall);
+ ASSERT(m_jitCodeForCallWithArityCheck);
+ return m_jitCodeForCallWithArityCheck;
+ }
+
+ MacroAssemblerCodePtr generatedJITCodeForConstructWithArityCheck()
+ {
+ ASSERT(m_jitCodeForConstruct);
+ ASSERT(m_jitCodeForConstructWithArityCheck);
+ return m_jitCodeForConstructWithArityCheck;
+ }
+
+ MacroAssemblerCodePtr generatedJITCodeWithArityCheckFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return generatedJITCodeForCallWithArityCheck();
+ ASSERT(kind == CodeForConstruct);
+ return generatedJITCodeForConstructWithArityCheck();
+ }
+
+ bool hasJITCodeForCall() const
+ {
+ return m_numParametersForCall >= 0;
+ }
+
+ bool hasJITCodeForConstruct() const
+ {
+ return m_numParametersForConstruct >= 0;
+ }
+
+ bool hasJITCodeFor(CodeSpecializationKind kind) const
+ {
+ if (kind == CodeForCall)
+ return hasJITCodeForCall();
+ ASSERT(kind == CodeForConstruct);
+ return hasJITCodeForConstruct();
+ }
+
+ // Intrinsics are only for calls, currently.
+ Intrinsic intrinsic() const;
+
+ Intrinsic intrinsicFor(CodeSpecializationKind kind) const
+ {
+ if (isCall(kind))
+ return intrinsic();
+ return NoIntrinsic;
+ }
+
+ protected:
+ JITCode m_jitCodeForCall;
+ JITCode m_jitCodeForConstruct;
+ MacroAssemblerCodePtr m_jitCodeForCallWithArityCheck;
+ MacroAssemblerCodePtr m_jitCodeForConstructWithArityCheck;
+#endif
+ void clearCode();
+ };
+
+ class NativeExecutable : public ExecutableBase {
+ friend class JIT;
+ public:
+ typedef ExecutableBase Base;
+
+#if ENABLE(JIT)
+ static NativeExecutable* create(JSGlobalData& globalData, MacroAssemblerCodeRef callThunk, NativeFunction function, MacroAssemblerCodeRef constructThunk, NativeFunction constructor, Intrinsic intrinsic)
+ {
+ ASSERT(globalData.canUseJIT());
+ NativeExecutable* executable;
+ if (!callThunk) {
+ executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
+ executable->finishCreation(globalData, JITCode(), JITCode(), intrinsic);
+ } else {
+ executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
+ executable->finishCreation(globalData, JITCode::HostFunction(callThunk), JITCode::HostFunction(constructThunk), intrinsic);
+ }
+ globalData.heap.addFinalizer(executable, &finalize);
+ return executable;
+ }
+#endif
+
+#if ENABLE(INTERPRETER)
+ static NativeExecutable* create(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
+ {
+ ASSERT(!globalData.canUseJIT());
+ NativeExecutable* executable = new (NotNull, allocateCell<NativeExecutable>(globalData.heap)) NativeExecutable(globalData, function, constructor);
+ executable->finishCreation(globalData);
+ globalData.heap.addFinalizer(executable, &finalize);
+ return executable;
+ }
+#endif
+
+ static void destroy(JSCell*);
+
+ NativeFunction function() { return m_function; }
+ NativeFunction constructor() { return m_constructor; }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(LeafType, StructureFlags), &s_info); }
+
+ static const ClassInfo s_info;
+
+ Intrinsic intrinsic() const;
+
+ protected:
+#if ENABLE(JIT)
+ void finishCreation(JSGlobalData& globalData, JITCode callThunk, JITCode constructThunk, Intrinsic intrinsic)
+ {
+ ASSERT(globalData.canUseJIT());
+ Base::finishCreation(globalData);
+ m_jitCodeForCall = callThunk;
+ m_jitCodeForConstruct = constructThunk;
+ m_jitCodeForCallWithArityCheck = callThunk.addressForCall();
+ m_jitCodeForConstructWithArityCheck = constructThunk.addressForCall();
+ m_intrinsic = intrinsic;
+ }
+#endif
+
+#if ENABLE(INTERPRETER)
+ void finishCreation(JSGlobalData& globalData)
+ {
+ ASSERT(!globalData.canUseJIT());
+ Base::finishCreation(globalData);
+ m_intrinsic = NoIntrinsic;
+ }
+#endif
+
+ static void finalize(JSCell*);
+
+ private:
+ NativeExecutable(JSGlobalData& globalData, NativeFunction function, NativeFunction constructor)
+ : ExecutableBase(globalData, globalData.nativeExecutableStructure.get(), NUM_PARAMETERS_IS_HOST)
+ , m_function(function)
+ , m_constructor(constructor)
+ {
+ }
+
+ NativeFunction m_function;
+ NativeFunction m_constructor;
+
+ Intrinsic m_intrinsic;
+ };
+
+ class ScriptExecutable : public ExecutableBase {
+ public:
+ typedef ExecutableBase Base;
+
+ ScriptExecutable(Structure* structure, JSGlobalData& globalData, const SourceCode& source, bool isInStrictContext)
+ : ExecutableBase(globalData, structure, NUM_PARAMETERS_NOT_COMPILED)
+ , m_source(source)
+ , m_features(isInStrictContext ? StrictModeFeature : 0)
+ {
+ }
+
+ ScriptExecutable(Structure* structure, ExecState* exec, const SourceCode& source, bool isInStrictContext)
+ : ExecutableBase(exec->globalData(), structure, NUM_PARAMETERS_NOT_COMPILED)
+ , m_source(source)
+ , m_features(isInStrictContext ? StrictModeFeature : 0)
+ {
+ }
+
+ static void destroy(JSCell*);
+
+ const SourceCode& source() { return m_source; }
+ intptr_t sourceID() const { return m_source.provider()->asID(); }
+ const UString& sourceURL() const { return m_source.provider()->url(); }
+ int lineNo() const { return m_firstLine; }
+ int lastLine() const { return m_lastLine; }
+
+ bool usesEval() const { return m_features & EvalFeature; }
+ bool usesArguments() const { return m_features & ArgumentsFeature; }
+ bool needsActivation() const { return m_hasCapturedVariables || m_features & (EvalFeature | WithFeature | CatchFeature); }
+ bool isStrictMode() const { return m_features & StrictModeFeature; }
+
+ void unlinkCalls();
+
+ static const ClassInfo s_info;
+
+ protected:
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData);
+#if ENABLE(CODEBLOCK_SAMPLING)
+ if (SamplingTool* sampler = globalData.interpreter->sampler())
+ sampler->notifyOfScope(globalData, this);
+#endif
+ }
+
+ void recordParse(CodeFeatures features, bool hasCapturedVariables, int firstLine, int lastLine)
+ {
+ m_features = features;
+ m_hasCapturedVariables = hasCapturedVariables;
+ m_firstLine = firstLine;
+ m_lastLine = lastLine;
+ }
+
+ SourceCode m_source;
+ CodeFeatures m_features;
+ bool m_hasCapturedVariables;
+ int m_firstLine;
+ int m_lastLine;
+ };
+
+ class EvalExecutable : public ScriptExecutable {
+ public:
+ typedef ScriptExecutable Base;
+
+ static void destroy(JSCell*);
+
+ JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
+ {
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ JSObject* error = 0;
+ if (!m_evalCodeBlock)
+ error = compileInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
+ ASSERT(!error == !!m_evalCodeBlock);
+ return error;
+ }
+
+ JSObject* compileOptimized(ExecState*, ScopeChainNode*);
+
+#if ENABLE(JIT)
+ void jettisonOptimizedCode(JSGlobalData&);
+#endif
+
+ EvalCodeBlock& generatedBytecode()
+ {
+ ASSERT(m_evalCodeBlock);
+ return *m_evalCodeBlock;
+ }
+
+ static EvalExecutable* create(ExecState* exec, const SourceCode& source, bool isInStrictContext)
+ {
+ EvalExecutable* executable = new (NotNull, allocateCell<EvalExecutable>(*exec->heap())) EvalExecutable(exec, source, isInStrictContext);
+ executable->finishCreation(exec->globalData());
+ exec->globalData().heap.addFinalizer(executable, &finalize);
+ return executable;
+ }
+
+#if ENABLE(JIT)
+ JITCode& generatedJITCode()
+ {
+ return generatedJITCodeForCall();
+ }
+#endif
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(globalData, globalObject, proto, TypeInfo(EvalExecutableType, StructureFlags), &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+ void unlinkCalls();
+
+ protected:
+ void clearCode();
+ static void finalize(JSCell*);
+
+ private:
+ static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+ EvalExecutable(ExecState*, const SourceCode&, bool);
+
+ JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ OwnPtr<EvalCodeBlock> m_evalCodeBlock;
+ };
+
+ class ProgramExecutable : public ScriptExecutable {
+ public:
+ typedef ScriptExecutable Base;
+
+ static ProgramExecutable* create(ExecState* exec, const SourceCode& source)
+ {
+ ProgramExecutable* executable = new (NotNull, allocateCell<ProgramExecutable>(*exec->heap())) ProgramExecutable(exec, source);
+ executable->finishCreation(exec->globalData());
+ exec->globalData().heap.addFinalizer(executable, &finalize);
+ return executable;
+ }
+
+ static void destroy(JSCell*);
+
+ JSObject* compile(ExecState* exec, ScopeChainNode* scopeChainNode)
+ {
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ JSObject* error = 0;
+ if (!m_programCodeBlock)
+ error = compileInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
+ ASSERT(!error == !!m_programCodeBlock);
+ return error;
+ }
+
+ JSObject* compileOptimized(ExecState*, ScopeChainNode*);
+
+#if ENABLE(JIT)
+ void jettisonOptimizedCode(JSGlobalData&);
+#endif
+
+ ProgramCodeBlock& generatedBytecode()
+ {
+ ASSERT(m_programCodeBlock);
+ return *m_programCodeBlock;
+ }
+
+ JSObject* checkSyntax(ExecState*);
+
+#if ENABLE(JIT)
+ JITCode& generatedJITCode()
+ {
+ return generatedJITCodeForCall();
+ }
+#endif
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(globalData, globalObject, proto, TypeInfo(ProgramExecutableType, StructureFlags), &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+ void unlinkCalls();
+
+ protected:
+ void clearCode();
+ static void finalize(JSCell*);
+
+ private:
+ static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+ ProgramExecutable(ExecState*, const SourceCode&);
+
+ JSObject* compileInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ OwnPtr<ProgramCodeBlock> m_programCodeBlock;
+ };
+
+ class FunctionExecutable : public ScriptExecutable {
+ friend class JIT;
+ public:
+ typedef ScriptExecutable Base;
+
+ static FunctionExecutable* create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
+ {
+ FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(*exec->heap())) FunctionExecutable(exec, name, source, forceUsesArguments, parameters, isInStrictContext);
+ executable->finishCreation(exec->globalData(), name, firstLine, lastLine);
+ exec->globalData().heap.addFinalizer(executable, &finalize);
+ return executable;
+ }
+
+ static FunctionExecutable* create(JSGlobalData& globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, bool isInStrictContext, int firstLine, int lastLine)
+ {
+ FunctionExecutable* executable = new (NotNull, allocateCell<FunctionExecutable>(globalData.heap)) FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, isInStrictContext);
+ executable->finishCreation(globalData, name, firstLine, lastLine);
+ globalData.heap.addFinalizer(executable, &finalize);
+ return executable;
+ }
+
+ static void destroy(JSCell*);
+
+ JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain)
+ {
+ return JSFunction::create(exec, this, scopeChain);
+ }
+
+ // Returns either call or construct bytecode. This can be appropriate
+ // for answering questions that that don't vary between call and construct --
+ // for example, argumentsRegister().
+ FunctionCodeBlock& generatedBytecode()
+ {
+ if (m_codeBlockForCall)
+ return *m_codeBlockForCall;
+ ASSERT(m_codeBlockForConstruct);
+ return *m_codeBlockForConstruct;
+ }
+
+ FunctionCodeBlock* codeBlockWithBytecodeFor(CodeSpecializationKind);
+
+ PassOwnPtr<FunctionCodeBlock> produceCodeBlockFor(ScopeChainNode*, CompilationKind, CodeSpecializationKind, JSObject*& exception);
+
+ JSObject* compileForCall(ExecState* exec, ScopeChainNode* scopeChainNode)
+ {
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ JSObject* error = 0;
+ if (!m_codeBlockForCall)
+ error = compileForCallInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
+ ASSERT(!error == !!m_codeBlockForCall);
+ return error;
+ }
+
+ JSObject* compileOptimizedForCall(ExecState*, ScopeChainNode*);
+
+#if ENABLE(JIT)
+ void jettisonOptimizedCodeForCall(JSGlobalData&);
+#endif
+
+ bool isGeneratedForCall() const
+ {
+ return m_codeBlockForCall;
+ }
+
+ FunctionCodeBlock& generatedBytecodeForCall()
+ {
+ ASSERT(m_codeBlockForCall);
+ return *m_codeBlockForCall;
+ }
+
+ JSObject* compileForConstruct(ExecState* exec, ScopeChainNode* scopeChainNode)
+ {
+ ASSERT(exec->globalData().dynamicGlobalObject);
+ JSObject* error = 0;
+ if (!m_codeBlockForConstruct)
+ error = compileForConstructInternal(exec, scopeChainNode, JITCode::bottomTierJIT());
+ ASSERT(!error == !!m_codeBlockForConstruct);
+ return error;
+ }
+
+ JSObject* compileOptimizedForConstruct(ExecState*, ScopeChainNode*);
+
+#if ENABLE(JIT)
+ void jettisonOptimizedCodeForConstruct(JSGlobalData&);
+#endif
+
+ bool isGeneratedForConstruct() const
+ {
+ return m_codeBlockForConstruct;
+ }
+
+ FunctionCodeBlock& generatedBytecodeForConstruct()
+ {
+ ASSERT(m_codeBlockForConstruct);
+ return *m_codeBlockForConstruct;
+ }
+
+ JSObject* compileFor(ExecState* exec, ScopeChainNode* scopeChainNode, CodeSpecializationKind kind)
+ {
+ ASSERT(exec->callee());
+ ASSERT(exec->callee()->inherits(&JSFunction::s_info));
+ ASSERT(asFunction(exec->callee())->jsExecutable() == this);
+
+ if (kind == CodeForCall)
+ return compileForCall(exec, scopeChainNode);
+ ASSERT(kind == CodeForConstruct);
+ return compileForConstruct(exec, scopeChainNode);
+ }
+
+ JSObject* compileOptimizedFor(ExecState* exec, ScopeChainNode* scopeChainNode, CodeSpecializationKind kind)
+ {
+ ASSERT(exec->callee());
+ ASSERT(exec->callee()->inherits(&JSFunction::s_info));
+ ASSERT(asFunction(exec->callee())->jsExecutable() == this);
+
+ if (kind == CodeForCall)
+ return compileOptimizedForCall(exec, scopeChainNode);
+ ASSERT(kind == CodeForConstruct);
+ return compileOptimizedForConstruct(exec, scopeChainNode);
+ }
+
+#if ENABLE(JIT)
+ void jettisonOptimizedCodeFor(JSGlobalData& globalData, CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ jettisonOptimizedCodeForCall(globalData);
+ else {
+ ASSERT(kind == CodeForConstruct);
+ jettisonOptimizedCodeForConstruct(globalData);
+ }
+ }
+#endif
+
+ bool isGeneratedFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return isGeneratedForCall();
+ ASSERT(kind == CodeForConstruct);
+ return isGeneratedForConstruct();
+ }
+
+ FunctionCodeBlock& generatedBytecodeFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return generatedBytecodeForCall();
+ ASSERT(kind == CodeForConstruct);
+ return generatedBytecodeForConstruct();
+ }
+
+ FunctionCodeBlock* baselineCodeBlockFor(CodeSpecializationKind);
+
+ FunctionCodeBlock* profiledCodeBlockFor(CodeSpecializationKind kind)
+ {
+ return baselineCodeBlockFor(kind);
+ }
+
+ const Identifier& name() { return m_name; }
+ JSString* nameValue() const { return m_nameValue.get(); }
+ size_t parameterCount() const { return m_parameters->size(); } // Excluding 'this'!
+ unsigned capturedVariableCount() const { return m_numCapturedVariables; }
+ UString paramString() const;
+ SharedSymbolTable* symbolTable() const { return m_symbolTable; }
+
+ void discardCode();
+ static void visitChildren(JSCell*, SlotVisitor&);
+ static FunctionExecutable* fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, JSObject** exception);
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(globalData, globalObject, proto, TypeInfo(FunctionExecutableType, StructureFlags), &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+ void unlinkCalls();
+
+ protected:
+ void clearCode();
+ static void finalize(JSCell*);
+
+ void finishCreation(JSGlobalData& globalData, const Identifier& name, int firstLine, int lastLine)
+ {
+ Base::finishCreation(globalData);
+ m_firstLine = firstLine;
+ m_lastLine = lastLine;
+ m_nameValue.set(globalData, this, jsString(&globalData, name.ustring()));
+ }
+
+ private:
+ FunctionExecutable(JSGlobalData&, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
+ FunctionExecutable(ExecState*, const Identifier& name, const SourceCode&, bool forceUsesArguments, FunctionParameters*, bool);
+
+ JSObject* compileForCallInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
+ JSObject* compileForConstructInternal(ExecState*, ScopeChainNode*, JITCode::JITType);
+
+ OwnPtr<FunctionCodeBlock>& codeBlockFor(CodeSpecializationKind kind)
+ {
+ if (kind == CodeForCall)
+ return m_codeBlockForCall;
+ ASSERT(kind == CodeForConstruct);
+ return m_codeBlockForConstruct;
+ }
+
+ static const unsigned StructureFlags = OverridesVisitChildren | ScriptExecutable::StructureFlags;
+ unsigned m_numCapturedVariables : 31;
+ bool m_forceUsesArguments : 1;
+
+ RefPtr<FunctionParameters> m_parameters;
+ OwnPtr<FunctionCodeBlock> m_codeBlockForCall;
+ OwnPtr<FunctionCodeBlock> m_codeBlockForConstruct;
+ Identifier m_name;
+ WriteBarrier<JSString> m_nameValue;
+ SharedSymbolTable* m_symbolTable;
+ };
+
+ inline FunctionExecutable* JSFunction::jsExecutable() const
+ {
+ ASSERT(!isHostFunctionNonInline());
+ return static_cast<FunctionExecutable*>(m_executable.get());
+ }
+
+ inline bool JSFunction::isHostFunction() const
+ {
+ ASSERT(m_executable);
+ return m_executable->isHostFunction();
+ }
+
+ inline NativeFunction JSFunction::nativeFunction()
+ {
+ ASSERT(isHostFunction());
+ return static_cast<NativeExecutable*>(m_executable.get())->function();
+ }
+
+ inline NativeFunction JSFunction::nativeConstructor()
+ {
+ ASSERT(isHostFunction());
+ return static_cast<NativeExecutable*>(m_executable.get())->constructor();
+ }
+
+ inline bool isHostFunction(JSValue value, NativeFunction nativeFunction)
+ {
+ JSFunction* function = static_cast<JSFunction*>(getJSFunction(value));
+ if (!function || !function->isHostFunction())
+ return false;
+ return function->nativeFunction() == nativeFunction;
+ }
+
+ inline void ScriptExecutable::unlinkCalls()
+ {
+ switch (structure()->typeInfo().type()) {
+ case EvalExecutableType:
+ return jsCast<EvalExecutable*>(this)->unlinkCalls();
+ case ProgramExecutableType:
+ return jsCast<ProgramExecutable*>(this)->unlinkCalls();
+ case FunctionExecutableType:
+ return jsCast<FunctionExecutable*>(this)->unlinkCalls();
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ }
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.cpp b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
new file mode 100644
index 000000000..e08e58c83
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.cpp
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "FunctionConstructor.h"
+
+#include "Debugger.h"
+#include "ExceptionHelpers.h"
+#include "FunctionPrototype.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "JSString.h"
+#include "Lexer.h"
+#include "Nodes.h"
+#include "Parser.h"
+#include "UStringBuilder.h"
+#include "UStringConcatenate.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(FunctionConstructor);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(FunctionConstructor);
+
+const ClassInfo FunctionConstructor::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionConstructor) };
+
+FunctionConstructor::FunctionConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void FunctionConstructor::finishCreation(ExecState* exec, FunctionPrototype* functionPrototype)
+{
+ Base::finishCreation(exec->globalData(), Identifier(exec, functionPrototype->classInfo()->className));
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly);
+
+ // Number of arguments for constructor
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWithFunctionConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args));
+}
+
+ConstructType FunctionConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithFunctionConstructor;
+ return ConstructTypeHost;
+}
+
+static EncodedJSValue JSC_HOST_CALL callFunctionConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructFunction(exec, asInternalFunction(exec->callee())->globalObject(), args));
+}
+
+// ECMA 15.3.1 The Function Constructor Called as a Function
+CallType FunctionConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callFunctionConstructor;
+ return CallTypeHost;
+}
+
+// ECMA 15.3.2 The Function Constructor
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const UString& sourceURL, const TextPosition& position)
+{
+ if (!globalObject->evalEnabled())
+ return throwError(exec, createEvalError(exec, "Function constructor is disabled"));
+ return constructFunctionSkippingEvalEnabledCheck(exec, globalObject, args, functionName, sourceURL, position);
+}
+
+JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args, const Identifier& functionName, const UString& sourceURL, const TextPosition& position)
+{
+ // Functions need to have a space following the opening { due to for web compatibility
+ // see https://bugs.webkit.org/show_bug.cgi?id=24350
+ // We also need \n before the closing } to handle // comments at the end of the last line
+ UString program;
+ if (args.isEmpty())
+ program = "(function() { \n})";
+ else if (args.size() == 1)
+ program = makeUString("(function() { ", args.at(0).toString(exec), "\n})");
+ else {
+ UStringBuilder builder;
+ builder.append("(function(");
+ builder.append(args.at(0).toString(exec));
+ for (size_t i = 1; i < args.size() - 1; i++) {
+ builder.append(",");
+ builder.append(args.at(i).toString(exec));
+ }
+ builder.append(") { ");
+ builder.append(args.at(args.size() - 1).toString(exec));
+ builder.append("\n})");
+ program = builder.toUString();
+ }
+
+ JSGlobalData& globalData = globalObject->globalData();
+ SourceCode source = makeSource(program, sourceURL, position);
+ JSObject* exception = 0;
+ FunctionExecutable* function = FunctionExecutable::fromGlobalCode(functionName, exec, exec->dynamicGlobalObject()->debugger(), source, &exception);
+ if (!function) {
+ ASSERT(exception);
+ return throwError(exec, exception);
+ }
+
+ ScopeChainNode* scopeChain = ScopeChainNode::create(exec, 0, globalObject, &globalData, globalObject, exec->globalThisValue());
+ return JSFunction::create(exec, function, scopeChain);
+}
+
+// ECMA 15.3.2 The Function Constructor
+JSObject* constructFunction(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
+{
+ return constructFunction(exec, globalObject, args, Identifier(exec, "anonymous"), UString(), TextPosition::minimumPosition());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/FunctionConstructor.h b/Source/JavaScriptCore/runtime/FunctionConstructor.h
new file mode 100644
index 000000000..7141916cf
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionConstructor.h
@@ -0,0 +1,66 @@
+/*
+ * 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 WTF {
+class TextPosition;
+}
+
+namespace JSC {
+
+ class FunctionPrototype;
+
+ class FunctionConstructor : public InternalFunction {
+ public:
+ typedef InternalFunction Base;
+
+ static FunctionConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, FunctionPrototype* functionPrototype)
+ {
+ FunctionConstructor* constructor = new (NotNull, allocateCell<FunctionConstructor>(*exec->heap())) FunctionConstructor(globalObject, structure);
+ constructor->finishCreation(exec, functionPrototype);
+ return constructor;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ private:
+ FunctionConstructor(JSGlobalObject*, Structure*);
+ void finishCreation(ExecState*, FunctionPrototype*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ };
+
+ JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&, const Identifier& functionName, const UString& sourceURL, const WTF::TextPosition&);
+ JSObject* constructFunction(ExecState*, JSGlobalObject*, const ArgList&);
+
+ JSObject* constructFunctionSkippingEvalEnabledCheck(ExecState*, JSGlobalObject*, const ArgList&, const Identifier&, const UString&, const WTF::TextPosition&);
+
+} // namespace JSC
+
+#endif // FunctionConstructor_h
diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.cpp b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
new file mode 100644
index 000000000..049b7b914
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionPrototype.cpp
@@ -0,0 +1,215 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "FunctionPrototype.h"
+
+#include "Arguments.h"
+#include "JSArray.h"
+#include "JSBoundFunction.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+#include "Interpreter.h"
+#include "Lexer.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(FunctionPrototype);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(FunctionPrototype);
+
+const ClassInfo FunctionPrototype::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(FunctionPrototype) };
+
+static EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*);
+static EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState*);
+
+FunctionPrototype::FunctionPrototype(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void FunctionPrototype::finishCreation(ExecState* exec, const Identifier& name)
+{
+ Base::finishCreation(exec->globalData(), name);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
+}
+
+void FunctionPrototype::addFunctionProperties(ExecState* exec, JSGlobalObject* globalObject, JSFunction** callFunction, JSFunction** applyFunction)
+{
+ JSFunction* toStringFunction = JSFunction::create(exec, globalObject, 0, exec->propertyNames().toString, functionProtoFuncToString);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().toString, toStringFunction, DontEnum);
+
+ *applyFunction = JSFunction::create(exec, globalObject, 2, exec->propertyNames().apply, functionProtoFuncApply);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().apply, *applyFunction, DontEnum);
+
+ *callFunction = JSFunction::create(exec, globalObject, 1, exec->propertyNames().call, functionProtoFuncCall);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().call, *callFunction, DontEnum);
+
+ JSFunction* bindFunction = JSFunction::create(exec, globalObject, 1, exec->propertyNames().bind, functionProtoFuncBind);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().bind, bindFunction, DontEnum);
+}
+
+static EncodedJSValue JSC_HOST_CALL callFunctionPrototype(ExecState*)
+{
+ return JSValue::encode(jsUndefined());
+}
+
+// ECMA 15.3.4
+CallType FunctionPrototype::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callFunctionPrototype;
+ return CallTypeHost;
+}
+
+// Functions
+
+// Compatibility hack for the Optimost JavaScript library. (See <rdar://problem/6595040>.)
+static inline void insertSemicolonIfNeeded(UString& functionBody)
+{
+ ASSERT(functionBody[0] == '{');
+ ASSERT(functionBody[functionBody.length() - 1] == '}');
+
+ for (size_t i = functionBody.length() - 2; i > 0; --i) {
+ UChar ch = functionBody[i];
+ if (!Lexer<UChar>::isWhiteSpace(ch) && !Lexer<UChar>::isLineTerminator(ch)) {
+ if (ch != ';' && ch != '}')
+ functionBody = makeUString(functionBody.substringSharingImpl(0, i + 1), ";", functionBody.substringSharingImpl(i + 1, functionBody.length() - (i + 1)));
+ return;
+ }
+ }
+}
+
+EncodedJSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.inherits(&JSFunction::s_info)) {
+ JSFunction* function = asFunction(thisValue);
+ if (function->isHostFunction())
+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}"));
+ FunctionExecutable* executable = function->jsExecutable();
+ UString sourceString = executable->source().toString();
+ insertSemicolonIfNeeded(sourceString);
+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "(", executable->paramString(), ") ", sourceString));
+ }
+
+ if (thisValue.inherits(&InternalFunction::s_info)) {
+ InternalFunction* function = asInternalFunction(thisValue);
+ return JSValue::encode(jsMakeNontrivialString(exec, "function ", function->name(exec), "() {\n [native code]\n}"));
+ }
+
+ return throwVMTypeError(exec);
+}
+
+EncodedJSValue JSC_HOST_CALL functionProtoFuncApply(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ CallData callData;
+ CallType callType = getCallData(thisValue, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+
+ JSValue array = exec->argument(1);
+
+ MarkedArgumentBuffer applyArgs;
+ if (!array.isUndefinedOrNull()) {
+ if (!array.isObject())
+ return throwVMTypeError(exec);
+ if (asObject(array)->classInfo() == &Arguments::s_info) {
+ if (asArguments(array)->length(exec) > Arguments::MaxArguments)
+ return JSValue::encode(throwStackOverflowError(exec));
+ asArguments(array)->fillArgList(exec, applyArgs);
+ } else if (isJSArray(array)) {
+ if (asArray(array)->length() > Arguments::MaxArguments)
+ return JSValue::encode(throwStackOverflowError(exec));
+ asArray(array)->fillArgList(exec, applyArgs);
+ } else {
+ unsigned length = asObject(array)->get(exec, exec->propertyNames().length).toUInt32(exec);
+ if (length > Arguments::MaxArguments)
+ return JSValue::encode(throwStackOverflowError(exec));
+
+ for (unsigned i = 0; i < length; ++i)
+ applyArgs.append(asObject(array)->get(exec, i));
+ }
+ }
+
+ return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), applyArgs));
+}
+
+EncodedJSValue JSC_HOST_CALL functionProtoFuncCall(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ CallData callData;
+ CallType callType = getCallData(thisValue, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+
+ ArgList args(exec);
+ ArgList callArgs;
+ args.getSlice(1, callArgs);
+ return JSValue::encode(call(exec, thisValue, callType, callData, exec->argument(0), callArgs));
+}
+
+// 15.3.4.5 Function.prototype.bind (thisArg [, arg1 [, arg2, ...]])
+EncodedJSValue JSC_HOST_CALL functionProtoFuncBind(ExecState* exec)
+{
+ JSGlobalObject* globalObject = exec->callee()->globalObject();
+
+ // Let Target be the this value.
+ JSValue target = exec->hostThisValue();
+
+ // If IsCallable(Target) is false, throw a TypeError exception.
+ CallData callData;
+ CallType callType = getCallData(target, callData);
+ if (callType == CallTypeNone)
+ return throwVMTypeError(exec);
+ // Primitive values are not callable.
+ ASSERT(target.isObject());
+ JSObject* targetObject = asObject(target);
+
+ // Let A be a new (possibly empty) internal list of all of the argument values provided after thisArg (arg1, arg2 etc), in order.
+ size_t numBoundArgs = exec->argumentCount() > 1 ? exec->argumentCount() - 1 : 0;
+ JSArray* boundArgs = JSArray::tryCreateUninitialized(exec->globalData(), globalObject->arrayStructure(), numBoundArgs);
+ if (!boundArgs)
+ return JSValue::encode(throwOutOfMemoryError(exec));
+
+ for (size_t i = 0; i < numBoundArgs; ++i)
+ boundArgs->initializeIndex(exec->globalData(), i, exec->argument(i + 1));
+ boundArgs->completeInitialization(numBoundArgs);
+
+ // If the [[Class]] internal property of Target is "Function", then ...
+ // Else set the length own property of F to 0.
+ unsigned length = 0;
+ if (targetObject->inherits(&JSFunction::s_info)) {
+ ASSERT(target.get(exec, exec->propertyNames().length).isNumber());
+ // a. Let L be the length property of Target minus the length of A.
+ // b. Set the length own property of F to either 0 or L, whichever is larger.
+ unsigned targetLength = (unsigned)target.get(exec, exec->propertyNames().length).asNumber();
+ if (targetLength > numBoundArgs)
+ length = targetLength - numBoundArgs;
+ }
+
+ Identifier name(exec, target.get(exec, exec->propertyNames().name).toString(exec));
+
+ return JSValue::encode(JSBoundFunction::create(exec, globalObject, targetObject, exec->argument(0), boundArgs, length, name));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/FunctionPrototype.h b/Source/JavaScriptCore/runtime/FunctionPrototype.h
new file mode 100644
index 000000000..7dd1c2418
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/FunctionPrototype.h
@@ -0,0 +1,58 @@
+/*
+ * 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:
+ typedef InternalFunction Base;
+
+ static FunctionPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ FunctionPrototype* prototype = new (NotNull, allocateCell<FunctionPrototype>(*exec->heap())) FunctionPrototype(globalObject, structure);
+ prototype->finishCreation(exec, exec->propertyNames().nullIdentifier);
+ return prototype;
+ }
+
+ void addFunctionProperties(ExecState*, JSGlobalObject*, JSFunction** callFunction, JSFunction** applyFunction);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+ protected:
+ void finishCreation(ExecState*, const Identifier& name);
+
+ private:
+ FunctionPrototype(JSGlobalObject*, Structure*);
+ static CallType getCallData(JSCell*, CallData&);
+ };
+
+} // namespace JSC
+
+#endif // FunctionPrototype_h
diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.cpp b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp
new file mode 100644
index 000000000..308d245a9
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GCActivityCallback.cpp
@@ -0,0 +1,54 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GCActivityCallback.h"
+
+namespace JSC {
+
+struct DefaultGCActivityCallbackPlatformData {
+};
+
+DefaultGCActivityCallback::DefaultGCActivityCallback(Heap*)
+{
+}
+
+DefaultGCActivityCallback::~DefaultGCActivityCallback()
+{
+}
+
+void DefaultGCActivityCallback::operator()()
+{
+}
+
+void DefaultGCActivityCallback::synchronize()
+{
+}
+
+}
+
diff --git a/Source/JavaScriptCore/runtime/GCActivityCallback.h b/Source/JavaScriptCore/runtime/GCActivityCallback.h
new file mode 100644
index 000000000..f40ebee5b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GCActivityCallback.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef GCActivityCallback_h
+#define GCActivityCallback_h
+
+#include <wtf/OwnPtr.h>
+#include <wtf/PassOwnPtr.h>
+
+#if USE(CF)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+namespace JSC {
+
+class Heap;
+
+class GCActivityCallback {
+public:
+ virtual ~GCActivityCallback() {}
+ virtual void operator()() {}
+ virtual void synchronize() {}
+
+protected:
+ GCActivityCallback() {}
+};
+
+struct DefaultGCActivityCallbackPlatformData;
+
+class DefaultGCActivityCallback : public GCActivityCallback {
+public:
+ static PassOwnPtr<DefaultGCActivityCallback> create(Heap*);
+
+ DefaultGCActivityCallback(Heap*);
+ ~DefaultGCActivityCallback();
+
+ void operator()();
+ void synchronize();
+
+#if USE(CF)
+protected:
+ DefaultGCActivityCallback(Heap*, CFRunLoopRef);
+ void commonConstructor(Heap*, CFRunLoopRef);
+#endif
+
+private:
+ OwnPtr<DefaultGCActivityCallbackPlatformData> d;
+};
+
+inline PassOwnPtr<DefaultGCActivityCallback> DefaultGCActivityCallback::create(Heap* heap)
+{
+ return adoptPtr(new DefaultGCActivityCallback(heap));
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp
new file mode 100644
index 000000000..2e878bfe3
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GCActivityCallbackCF.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "GCActivityCallback.h"
+
+#include "APIShims.h"
+#include "Heap.h"
+#include "JSGlobalData.h"
+#include "JSLock.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
+#include <wtf/RetainPtr.h>
+#include <wtf/WTFThreadData.h>
+
+#if !USE(CF)
+#error "This file should only be used on CF platforms."
+#endif
+
+namespace JSC {
+
+struct DefaultGCActivityCallbackPlatformData {
+ static void trigger(CFRunLoopTimerRef, void *info);
+
+ RetainPtr<CFRunLoopTimerRef> timer;
+ RetainPtr<CFRunLoopRef> runLoop;
+ CFRunLoopTimerContext context;
+};
+
+const CFTimeInterval decade = 60 * 60 * 24 * 365 * 10;
+const CFTimeInterval triggerInterval = 2; // seconds
+
+void DefaultGCActivityCallbackPlatformData::trigger(CFRunLoopTimerRef timer, void *info)
+{
+ Heap* heap = static_cast<Heap*>(info);
+ APIEntryShim shim(heap->globalData());
+ heap->collectAllGarbage();
+ CFRunLoopTimerSetNextFireDate(timer, CFAbsoluteTimeGetCurrent() + decade);
+}
+
+DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap)
+{
+ commonConstructor(heap, CFRunLoopGetCurrent());
+}
+
+DefaultGCActivityCallback::DefaultGCActivityCallback(Heap* heap, CFRunLoopRef runLoop)
+{
+ commonConstructor(heap, runLoop);
+}
+
+DefaultGCActivityCallback::~DefaultGCActivityCallback()
+{
+ CFRunLoopRemoveTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
+ CFRunLoopTimerInvalidate(d->timer.get());
+ d->context.info = 0;
+ d->runLoop = 0;
+ d->timer = 0;
+}
+
+void DefaultGCActivityCallback::commonConstructor(Heap* heap, CFRunLoopRef runLoop)
+{
+ d = adoptPtr(new DefaultGCActivityCallbackPlatformData);
+
+ memset(&d->context, 0, sizeof(CFRunLoopTimerContext));
+ d->context.info = heap;
+ d->runLoop = runLoop;
+ d->timer.adoptCF(CFRunLoopTimerCreate(0, decade, decade, 0, 0, DefaultGCActivityCallbackPlatformData::trigger, &d->context));
+ CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
+}
+
+void DefaultGCActivityCallback::operator()()
+{
+ CFRunLoopTimerSetNextFireDate(d->timer.get(), CFAbsoluteTimeGetCurrent() + triggerInterval);
+}
+
+void DefaultGCActivityCallback::synchronize()
+{
+ if (CFRunLoopGetCurrent() == d->runLoop.get())
+ return;
+ CFRunLoopRemoveTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
+ d->runLoop = CFRunLoopGetCurrent();
+ CFRunLoopAddTimer(d->runLoop.get(), d->timer.get(), kCFRunLoopCommonModes);
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/GetterSetter.cpp b/Source/JavaScriptCore/runtime/GetterSetter.cpp
new file mode 100644
index 000000000..920399dda
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GetterSetter.cpp
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2004, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * 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 {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(GetterSetter);
+
+const ClassInfo GetterSetter::s_info = { "GetterSetter", 0, 0, 0, CREATE_METHOD_TABLE(GetterSetter) };
+
+void GetterSetter::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ GetterSetter* thisObject = jsCast<GetterSetter*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ JSCell::visitChildren(thisObject, visitor);
+
+ if (thisObject->m_getter)
+ visitor.append(&thisObject->m_getter);
+ if (thisObject->m_setter)
+ visitor.append(&thisObject->m_setter);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/GetterSetter.h b/Source/JavaScriptCore/runtime/GetterSetter.h
new file mode 100644
index 000000000..293bf6434
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/GetterSetter.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 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"
+
+#include "CallFrame.h"
+#include "Structure.h"
+
+namespace JSC {
+
+ class JSObject;
+
+ // This is an internal value object which stores getter and setter functions
+ // for a property.
+ class GetterSetter : public JSCell {
+ friend class JIT;
+
+ private:
+ GetterSetter(ExecState* exec)
+ : JSCell(exec->globalData(), exec->globalData().getterSetterStructure.get())
+ {
+ }
+
+ public:
+ typedef JSCell Base;
+
+ static GetterSetter* create(ExecState* exec)
+ {
+ GetterSetter* getterSetter = new (NotNull, allocateCell<GetterSetter>(*exec->heap())) GetterSetter(exec);
+ getterSetter->finishCreation(exec->globalData());
+ return getterSetter;
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ JSObject* getter() const { return m_getter.get(); }
+ void setGetter(JSGlobalData& globalData, JSObject* getter) { m_getter.set(globalData, this, getter); }
+ JSObject* setter() const { return m_setter.get(); }
+ void setSetter(JSGlobalData& globalData, JSObject* setter) { m_setter.set(globalData, this, setter); }
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(GetterSetterType, OverridesVisitChildren), &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+ private:
+ WriteBarrier<JSObject> m_getter;
+ WriteBarrier<JSObject> m_setter;
+ };
+
+ GetterSetter* asGetterSetter(JSValue);
+
+ inline GetterSetter* asGetterSetter(JSValue value)
+ {
+ ASSERT(value.asCell()->isGetterSetter());
+ return static_cast<GetterSetter*>(value.asCell());
+ }
+
+
+} // namespace JSC
+
+#endif // GetterSetter_h
diff --git a/Source/JavaScriptCore/runtime/Identifier.cpp b/Source/JavaScriptCore/runtime/Identifier.cpp
new file mode 100644
index 000000000..0d233e355
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Identifier.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Identifier.h"
+
+#include "CallFrame.h"
+#include "JSObject.h"
+#include "NumericStrings.h"
+#include "ScopeChain.h"
+#include <new> // for placement new
+#include <string.h> // for strlen
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/HashSet.h>
+#include <wtf/text/StringHash.h>
+
+using WTF::ThreadSpecific;
+
+namespace JSC {
+
+IdentifierTable::~IdentifierTable()
+{
+ HashSet<StringImpl*>::iterator end = m_table.end();
+ for (HashSet<StringImpl*>::iterator iter = m_table.begin(); iter != end; ++iter)
+ (*iter)->setIsIdentifier(false);
+}
+
+std::pair<HashSet<StringImpl*>::iterator, bool> IdentifierTable::add(StringImpl* value)
+{
+ std::pair<HashSet<StringImpl*>::iterator, bool> result = m_table.add(value);
+ (*result.first)->setIsIdentifier(true);
+ return result;
+}
+
+IdentifierTable* createIdentifierTable()
+{
+ return new IdentifierTable;
+}
+
+void deleteIdentifierTable(IdentifierTable* table)
+{
+ delete table;
+}
+
+struct IdentifierCStringTranslator {
+ static unsigned hash(const LChar* c)
+ {
+ return StringHasher::computeHash<LChar>(c);
+ }
+
+ static bool equal(StringImpl* r, const LChar* s)
+ {
+ return Identifier::equal(r, s);
+ }
+
+ static void translate(StringImpl*& location, const LChar* c, unsigned hash)
+ {
+ size_t length = strlen(reinterpret_cast<const char*>(c));
+ LChar* d;
+ StringImpl* r = StringImpl::createUninitialized(length, d).leakRef();
+ for (size_t i = 0; i != length; i++)
+ d[i] = c[i];
+ r->setHash(hash);
+ location = r;
+ }
+};
+
+struct IdentifierLCharFromUCharTranslator {
+ static unsigned hash(const CharBuffer<UChar>& buf)
+ {
+ return StringHasher::computeHash<UChar>(buf.s, buf.length);
+ }
+
+ static bool equal(StringImpl* str, const CharBuffer<UChar>& buf)
+ {
+ return Identifier::equal(str, buf.s, buf.length);
+ }
+
+ static void translate(StringImpl*& location, const CharBuffer<UChar>& buf, unsigned hash)
+ {
+ LChar* d;
+ StringImpl* r = StringImpl::createUninitialized(buf.length, d).leakRef();
+ for (unsigned i = 0; i != buf.length; i++) {
+ UChar c = buf.s[i];
+ ASSERT(c <= 0xff);
+ d[i] = c;
+ }
+ r->setHash(hash);
+ location = r;
+ }
+};
+
+PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const char* c)
+{
+ if (!c)
+ return 0;
+ if (!c[0])
+ return StringImpl::empty();
+ if (!c[1])
+ return add(globalData, globalData->smallStrings.singleCharacterStringRep(c[0]));
+
+ IdentifierTable& identifierTable = *globalData->identifierTable;
+ LiteralIdentifierTable& literalIdentifierTable = identifierTable.literalTable();
+
+ const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c);
+ if (iter != literalIdentifierTable.end())
+ return iter->second;
+
+ pair<HashSet<StringImpl*>::iterator, bool> addResult = identifierTable.add<const LChar*, IdentifierCStringTranslator>(reinterpret_cast<const LChar*>(c));
+
+ // If the string is newly-translated, then we need to adopt it.
+ // The boolean in the pair tells us if that is so.
+ RefPtr<StringImpl> addedString = addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+
+ literalIdentifierTable.add(c, addedString.get());
+
+ return addedString.release();
+}
+
+PassRefPtr<StringImpl> Identifier::add(ExecState* exec, const char* c)
+{
+ return add(&exec->globalData(), c);
+}
+
+PassRefPtr<StringImpl> Identifier::add8(JSGlobalData* globalData, const UChar* s, int length)
+{
+ if (length == 1) {
+ UChar c = s[0];
+ ASSERT(c <= 0xff);
+ if (canUseSingleCharacterString(c))
+ return add(globalData, globalData->smallStrings.singleCharacterStringRep(c));
+ }
+
+ if (!length)
+ return StringImpl::empty();
+ CharBuffer<UChar> buf = {s, length};
+ pair<HashSet<StringImpl*>::iterator, bool> addResult = globalData->identifierTable->add<CharBuffer<UChar>, IdentifierLCharFromUCharTranslator >(buf);
+
+ // If the string is newly-translated, then we need to adopt it.
+ // The boolean in the pair tells us if that is so.
+ return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+}
+
+template <typename CharType>
+ALWAYS_INLINE uint32_t Identifier::toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok)
+{
+ // Get the first character, turning it into a digit.
+ uint32_t value = characters[0] - '0';
+ if (value > 9)
+ return 0;
+
+ // Check for leading zeros. If the first characher is 0, then the
+ // length of the string must be one - e.g. "042" is not equal to "42".
+ if (!value && length > 1)
+ return 0;
+
+ while (--length) {
+ // Multiply value by 10, checking for overflow out of 32 bits.
+ if (value > 0xFFFFFFFFU / 10)
+ return 0;
+ value *= 10;
+
+ // Get the next character, turning it into a digit.
+ uint32_t newValue = *(++characters) - '0';
+ if (newValue > 9)
+ return 0;
+
+ // Add in the old value, checking for overflow out of 32 bits.
+ newValue += value;
+ if (newValue < value)
+ return 0;
+ value = newValue;
+ }
+
+ ok = true;
+ return value;
+}
+
+uint32_t Identifier::toUInt32(const UString& string, bool& ok)
+{
+ ok = false;
+
+ unsigned length = string.length();
+
+ // An empty string is not a number.
+ if (!length)
+ return 0;
+
+ if (string.is8Bit())
+ return toUInt32FromCharacters(string.characters8(), length, ok);
+ return toUInt32FromCharacters(string.characters16(), length, ok);
+}
+
+PassRefPtr<StringImpl> Identifier::addSlowCase(JSGlobalData* globalData, StringImpl* r)
+{
+ ASSERT(!r->isIdentifier());
+ // The empty & null strings are static singletons, and static strings are handled
+ // in ::add() in the header, so we should never get here with a zero length string.
+ ASSERT(r->length());
+
+ if (r->length() == 1) {
+ UChar c = (*r)[0];
+ if (c <= maxSingleCharacterString)
+ r = globalData->smallStrings.singleCharacterStringRep(c);
+ if (r->isIdentifier())
+ return r;
+ }
+
+ return *globalData->identifierTable->add(r).first;
+}
+
+PassRefPtr<StringImpl> Identifier::addSlowCase(ExecState* exec, StringImpl* r)
+{
+ return addSlowCase(&exec->globalData(), r);
+}
+
+Identifier Identifier::from(ExecState* exec, unsigned value)
+{
+ return Identifier(exec, exec->globalData().numericStrings.add(value));
+}
+
+Identifier Identifier::from(ExecState* exec, int value)
+{
+ return Identifier(exec, exec->globalData().numericStrings.add(value));
+}
+
+Identifier Identifier::from(ExecState* exec, double value)
+{
+ return Identifier(exec, exec->globalData().numericStrings.add(value));
+}
+
+Identifier Identifier::from(JSGlobalData* globalData, unsigned value)
+{
+ return Identifier(globalData, globalData->numericStrings.add(value));
+}
+
+Identifier Identifier::from(JSGlobalData* globalData, int value)
+{
+ return Identifier(globalData, globalData->numericStrings.add(value));
+}
+
+Identifier Identifier::from(JSGlobalData* globalData, double value)
+{
+ return Identifier(globalData, globalData->numericStrings.add(value));
+}
+
+#ifndef NDEBUG
+
+void Identifier::checkCurrentIdentifierTable(JSGlobalData* globalData)
+{
+ // Check the identifier table accessible through the threadspecific matches the
+ // globalData's identifier table.
+ ASSERT_UNUSED(globalData, globalData->identifierTable == wtfThreadData().currentIdentifierTable());
+}
+
+void Identifier::checkCurrentIdentifierTable(ExecState* exec)
+{
+ checkCurrentIdentifierTable(&exec->globalData());
+}
+
+#else
+
+// These only exists so that our exports are the same for debug and release builds.
+// This would be an ASSERT_NOT_REACHED(), but we're in NDEBUG only code here!
+NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentIdentifierTable(JSGlobalData*) { CRASH(); }
+NO_RETURN_DUE_TO_CRASH void Identifier::checkCurrentIdentifierTable(ExecState*) { CRASH(); }
+
+#endif
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Identifier.h b/Source/JavaScriptCore/runtime/Identifier.h
new file mode 100644
index 000000000..2cc88b256
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Identifier.h
@@ -0,0 +1,258 @@
+/*
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Identifier_h
+#define Identifier_h
+
+#include "JSGlobalData.h"
+#include "ThreadSpecific.h"
+#include "UString.h"
+#include <wtf/WTFThreadData.h>
+#include <wtf/text/CString.h>
+
+namespace JSC {
+
+ class ExecState;
+
+ class Identifier {
+ friend class Structure;
+ public:
+ Identifier() { }
+
+ Identifier(ExecState* exec, const char* s) : m_string(add(exec, s)) { } // Only to be used with string literals.
+ Identifier(ExecState* exec, StringImpl* rep) : m_string(add(exec, rep)) { }
+ Identifier(ExecState* exec, const UString& s) : m_string(add(exec, s.impl())) { }
+
+ Identifier(JSGlobalData* globalData, const char* s) : m_string(add(globalData, s)) { } // Only to be used with string literals.
+ Identifier(JSGlobalData* globalData, const LChar* s, int length) : m_string(add(globalData, s, length)) { }
+ Identifier(JSGlobalData* globalData, const UChar* s, int length) : m_string(add(globalData, s, length)) { }
+ Identifier(JSGlobalData* globalData, StringImpl* rep) : m_string(add(globalData, rep)) { }
+ Identifier(JSGlobalData* globalData, const UString& s) : m_string(add(globalData, s.impl())) { }
+
+ const UString& ustring() const { return m_string; }
+ StringImpl* impl() const { return m_string.impl(); }
+
+ const UChar* characters() const { return m_string.characters(); }
+ int length() const { return m_string.length(); }
+
+ CString ascii() const { return m_string.ascii(); }
+
+ static Identifier createLCharFromUChar(JSGlobalData* globalData, const UChar* s, int length) { return Identifier(globalData, add8(globalData, s, length)); }
+
+ static Identifier from(ExecState* exec, unsigned y);
+ static Identifier from(ExecState* exec, int y);
+ static Identifier from(ExecState* exec, double y);
+ static Identifier from(JSGlobalData*, unsigned y);
+ static Identifier from(JSGlobalData*, int y);
+ static Identifier from(JSGlobalData*, double y);
+
+ static uint32_t toUInt32(const UString&, bool& ok);
+ uint32_t toUInt32(bool& ok) const { return toUInt32(m_string, ok); }
+ unsigned toArrayIndex(bool& ok) const;
+
+ bool isNull() const { return m_string.isNull(); }
+ bool isEmpty() const { return m_string.isEmpty(); }
+
+ friend bool operator==(const Identifier&, const Identifier&);
+ friend bool operator!=(const Identifier&, const Identifier&);
+
+ friend bool operator==(const Identifier&, const LChar*);
+ friend bool operator==(const Identifier&, const char*);
+ friend bool operator!=(const Identifier&, const LChar*);
+ friend bool operator!=(const Identifier&, const char*);
+
+ static bool equal(const StringImpl*, const LChar*);
+ static inline bool equal(const StringImpl*a, const char*b) { return Identifier::equal(a, reinterpret_cast<const LChar*>(b)); };
+ static bool equal(const StringImpl*, const LChar*, unsigned length);
+ static bool equal(const StringImpl*, const UChar*, unsigned length);
+ static bool equal(const StringImpl* a, const StringImpl* b) { return ::equal(a, b); }
+
+ static PassRefPtr<StringImpl> add(ExecState*, const char*); // Only to be used with string literals.
+ static PassRefPtr<StringImpl> add(JSGlobalData*, const char*); // Only to be used with string literals.
+
+ private:
+ UString m_string;
+
+ template <typename CharType>
+ ALWAYS_INLINE static uint32_t toUInt32FromCharacters(const CharType* characters, unsigned length, bool& ok);
+
+ static bool equal(const Identifier& a, const Identifier& b) { return a.m_string.impl() == b.m_string.impl(); }
+ static bool equal(const Identifier& a, const LChar* b) { return equal(a.m_string.impl(), b); }
+
+ template <typename T> static PassRefPtr<StringImpl> add(JSGlobalData*, const T*, int length);
+ static PassRefPtr<StringImpl> add8(JSGlobalData*, const UChar*, int length);
+ template <typename T> ALWAYS_INLINE static bool canUseSingleCharacterString(T);
+
+ static PassRefPtr<StringImpl> add(ExecState* exec, StringImpl* r)
+ {
+#ifndef NDEBUG
+ checkCurrentIdentifierTable(exec);
+#endif
+ if (r->isIdentifier())
+ return r;
+ return addSlowCase(exec, r);
+ }
+ static PassRefPtr<StringImpl> add(JSGlobalData* globalData, StringImpl* r)
+ {
+#ifndef NDEBUG
+ checkCurrentIdentifierTable(globalData);
+#endif
+ if (r->isIdentifier())
+ return r;
+ return addSlowCase(globalData, r);
+ }
+
+ static PassRefPtr<StringImpl> addSlowCase(ExecState*, StringImpl* r);
+ static PassRefPtr<StringImpl> addSlowCase(JSGlobalData*, StringImpl* r);
+
+ static void checkCurrentIdentifierTable(ExecState*);
+ static void checkCurrentIdentifierTable(JSGlobalData*);
+ };
+
+ template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(LChar)
+ {
+ ASSERT(maxSingleCharacterString == 0xff);
+ return true;
+ }
+
+ template <> ALWAYS_INLINE bool Identifier::canUseSingleCharacterString(UChar c)
+ {
+ return (c <= maxSingleCharacterString);
+ }
+
+ template <typename T>
+ struct CharBuffer {
+ const T* s;
+ unsigned int length;
+ };
+
+ template <typename T>
+ struct IdentifierCharBufferTranslator {
+ static unsigned hash(const CharBuffer<T>& buf)
+ {
+ return StringHasher::computeHash<T>(buf.s, buf.length);
+ }
+
+ static bool equal(StringImpl* str, const CharBuffer<T>& buf)
+ {
+ return Identifier::equal(str, buf.s, buf.length);
+ }
+
+ static void translate(StringImpl*& location, const CharBuffer<T>& buf, unsigned hash)
+ {
+ T* d;
+ StringImpl* r = StringImpl::createUninitialized(buf.length, d).leakRef();
+ for (unsigned i = 0; i != buf.length; i++)
+ d[i] = buf.s[i];
+ r->setHash(hash);
+ location = r;
+ }
+ };
+
+ template <typename T>
+ PassRefPtr<StringImpl> Identifier::add(JSGlobalData* globalData, const T* s, int length)
+ {
+ if (length == 1) {
+ T c = s[0];
+ if (canUseSingleCharacterString(c))
+ return add(globalData, globalData->smallStrings.singleCharacterStringRep(c));
+ }
+
+ if (!length)
+ return StringImpl::empty();
+ CharBuffer<T> buf = {s, length};
+ pair<HashSet<StringImpl*>::iterator, bool> addResult = globalData->identifierTable->add<CharBuffer<T>, IdentifierCharBufferTranslator<T> >(buf);
+
+ // If the string is newly-translated, then we need to adopt it.
+ // The boolean in the pair tells us if that is so.
+ return addResult.second ? adoptRef(*addResult.first) : *addResult.first;
+ }
+
+ inline bool operator==(const Identifier& a, const Identifier& b)
+ {
+ return Identifier::equal(a, b);
+ }
+
+ inline bool operator!=(const Identifier& a, const Identifier& b)
+ {
+ return !Identifier::equal(a, b);
+ }
+
+ inline bool operator==(const Identifier& a, const LChar* b)
+ {
+ return Identifier::equal(a, b);
+ }
+
+ inline bool operator==(const Identifier& a, const char* b)
+ {
+ return Identifier::equal(a, reinterpret_cast<const LChar*>(b));
+ }
+
+ inline bool operator!=(const Identifier& a, const LChar* b)
+ {
+ return !Identifier::equal(a, b);
+ }
+
+ inline bool operator!=(const Identifier& a, const char* b)
+ {
+ return !Identifier::equal(a, reinterpret_cast<const LChar*>(b));
+ }
+
+ inline bool Identifier::equal(const StringImpl* r, const LChar* s)
+ {
+ return WTF::equal(r, s);
+ }
+
+ inline bool Identifier::equal(const StringImpl* r, const LChar* s, unsigned length)
+ {
+ return WTF::equal(r, s, length);
+ }
+
+ inline bool Identifier::equal(const StringImpl* r, const UChar* s, unsigned length)
+ {
+ return WTF::equal(r, s, length);
+ }
+
+ IdentifierTable* createIdentifierTable();
+ void deleteIdentifierTable(IdentifierTable*);
+
+ struct IdentifierRepHash : PtrHash<RefPtr<StringImpl> > {
+ static unsigned hash(const RefPtr<StringImpl>& key) { return key->existingHash(); }
+ static unsigned hash(StringImpl* key) { return key->existingHash(); }
+ };
+
+ struct IdentifierMapIndexHashTraits : HashTraits<int> {
+ static int emptyValue() { return std::numeric_limits<int>::max(); }
+ static const bool emptyValueIsZero = false;
+ };
+
+ typedef HashMap<RefPtr<StringImpl>, int, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, IdentifierMapIndexHashTraits> IdentifierMap;
+
+ template<typename U, typename V>
+ std::pair<HashSet<StringImpl*>::iterator, bool> IdentifierTable::add(U value)
+ {
+ std::pair<HashSet<StringImpl*>::iterator, bool> result = m_table.add<U, V>(value);
+ (*result.first)->setIsIdentifier(true);
+ return result;
+ }
+
+} // namespace JSC
+
+#endif // Identifier_h
diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.cpp b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
new file mode 100644
index 000000000..2b874c708
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InitializeThreading.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 "ExecutableAllocator.h"
+#include "Heap.h"
+#include "Options.h"
+#include "Identifier.h"
+#include "JSDateMath.h"
+#include "JSGlobalObject.h"
+#include "UString.h"
+#include "WriteBarrier.h"
+#include "dtoa.h"
+#include <wtf/Threading.h>
+#include <wtf/dtoa/cached-powers.h>
+
+using namespace WTF;
+
+namespace JSC {
+
+#if OS(DARWIN)
+static pthread_once_t initializeThreadingKeyOnce = PTHREAD_ONCE_INIT;
+#endif
+
+static void initializeThreadingOnce()
+{
+ WTF::double_conversion::initialize();
+ WTF::initializeThreading();
+ Options::initializeOptions();
+#if ENABLE(WRITE_BARRIER_PROFILING)
+ WriteBarrierCounters::initialize();
+#endif
+#if ENABLE(JIT) && ENABLE(ASSEMBLER)
+ ExecutableAllocator::initializeAllocator();
+#endif
+ RegisterFile::initializeThreading();
+}
+
+void initializeThreading()
+{
+#if OS(DARWIN)
+ pthread_once(&initializeThreadingKeyOnce, initializeThreadingOnce);
+#else
+ static bool initializedThreading = false;
+ if (!initializedThreading) {
+ initializeThreadingOnce();
+ initializedThreading = true;
+ }
+#endif
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/InitializeThreading.h b/Source/JavaScriptCore/runtime/InitializeThreading.h
new file mode 100644
index 000000000..1a93ccb9b
--- /dev/null
+++ b/Source/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/Source/JavaScriptCore/runtime/InternalFunction.cpp b/Source/JavaScriptCore/runtime/InternalFunction.cpp
new file mode 100644
index 000000000..50ea504c1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InternalFunction.cpp
@@ -0,0 +1,81 @@
+/*
+ * 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 "JSGlobalObject.h"
+#include "JSString.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(InternalFunction);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(InternalFunction);
+
+const ClassInfo InternalFunction::s_info = { "Function", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(InternalFunction) };
+
+InternalFunction::InternalFunction(JSGlobalObject* globalObject, Structure* structure)
+ : JSNonFinalObject(globalObject->globalData(), structure)
+{
+}
+
+void InternalFunction::finishCreation(JSGlobalData& globalData, const Identifier& name)
+{
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+ ASSERT(methodTable()->getCallData != InternalFunction::s_info.methodTable.getCallData);
+ putDirect(globalData, globalData.propertyNames->name, jsString(&globalData, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
+}
+
+const UString& InternalFunction::name(ExecState* exec)
+{
+ return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue();
+}
+
+const UString InternalFunction::displayName(ExecState* exec)
+{
+ JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName);
+
+ if (displayName && isJSString(displayName))
+ return asString(displayName)->tryGetValue();
+
+ return UString();
+}
+
+CallType InternalFunction::getCallData(JSCell*, CallData&)
+{
+ ASSERT_NOT_REACHED();
+ return CallTypeNone;
+}
+
+const UString InternalFunction::calculatedDisplayName(ExecState* exec)
+{
+ const UString explicitName = displayName(exec);
+
+ if (!explicitName.isEmpty())
+ return explicitName;
+
+ return name(exec);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/InternalFunction.h b/Source/JavaScriptCore/runtime/InternalFunction.h
new file mode 100644
index 000000000..a038b7ae1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/InternalFunction.h
@@ -0,0 +1,69 @@
+/*
+ * 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 JSNonFinalObject {
+ public:
+ typedef JSNonFinalObject Base;
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ const UString& name(ExecState*);
+ const UString displayName(ExecState*);
+ const UString calculatedDisplayName(ExecState*);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags;
+
+ InternalFunction(JSGlobalObject*, Structure*);
+
+ void finishCreation(JSGlobalData&, const Identifier& name);
+
+ static CallType getCallData(JSCell*, CallData&);
+ };
+
+ InternalFunction* asInternalFunction(JSValue);
+
+ inline InternalFunction* asInternalFunction(JSValue value)
+ {
+ ASSERT(asObject(value)->inherits(&InternalFunction::s_info));
+ return static_cast<InternalFunction*>(asObject(value));
+ }
+
+} // namespace JSC
+
+#endif // InternalFunction_h
diff --git a/Source/JavaScriptCore/runtime/Intrinsic.h b/Source/JavaScriptCore/runtime/Intrinsic.h
new file mode 100644
index 000000000..5cc00685f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Intrinsic.h
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Intrinsic_h
+#define Intrinsic_h
+
+namespace JSC {
+
+enum Intrinsic {
+ NoIntrinsic,
+ AbsIntrinsic,
+ MinIntrinsic,
+ MaxIntrinsic,
+ SqrtIntrinsic,
+ ArrayPushIntrinsic,
+ ArrayPopIntrinsic,
+ CharCodeAtIntrinsic,
+ CharAtIntrinsic,
+ FromCharCodeIntrinsic,
+ PowIntrinsic,
+ FloorIntrinsic,
+ CeilIntrinsic,
+ RoundIntrinsic,
+ ExpIntrinsic,
+ LogIntrinsic,
+};
+
+} // namespace JSC
+
+#endif // Intrinsic_h
diff --git a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp
new file mode 100644
index 000000000..8517085df
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.cpp
@@ -0,0 +1,35 @@
+/*
+ * 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 "JSAPIValueWrapper.h"
+
+#include "NumberObject.h"
+#include "UString.h"
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSAPIValueWrapper);
+
+const ClassInfo JSAPIValueWrapper::s_info = { "API Wrapper", 0, 0, 0, CREATE_METHOD_TABLE(JSAPIValueWrapper) };
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h
new file mode 100644
index 000000000..21d7b215c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSAPIValueWrapper.h
@@ -0,0 +1,78 @@
+/*
+ * 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 JSAPIValueWrapper_h
+#define JSAPIValueWrapper_h
+
+#include "JSCell.h"
+#include "JSValue.h"
+#include "CallFrame.h"
+#include "Structure.h"
+
+namespace JSC {
+
+ class JSAPIValueWrapper : public JSCell {
+ friend JSValue jsAPIValueWrapper(ExecState*, JSValue);
+ public:
+ typedef JSCell Base;
+
+ JSValue value() const { return m_value.get(); }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(APIValueWrapperType, OverridesVisitChildren | OverridesGetPropertyNames), &s_info);
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ static JSAPIValueWrapper* create(ExecState* exec, JSValue value)
+ {
+ JSAPIValueWrapper* wrapper = new (NotNull, allocateCell<JSAPIValueWrapper>(*exec->heap())) JSAPIValueWrapper(exec);
+ wrapper->finishCreation(exec, value);
+ return wrapper;
+ }
+
+ protected:
+ void finishCreation(ExecState* exec, JSValue value)
+ {
+ Base::finishCreation(exec->globalData());
+ m_value.set(exec->globalData(), this, value);
+ ASSERT(!value.isCell());
+ }
+
+ private:
+ JSAPIValueWrapper(ExecState* exec)
+ : JSCell(exec->globalData(), exec->globalData().apiWrapperStructure.get())
+ {
+ }
+
+ WriteBarrier<Unknown> m_value;
+ };
+
+ inline JSValue jsAPIValueWrapper(ExecState* exec, JSValue value)
+ {
+ return JSAPIValueWrapper::create(exec, value);
+ }
+
+} // namespace JSC
+
+#endif // JSAPIValueWrapper_h
diff --git a/Source/JavaScriptCore/runtime/JSActivation.cpp b/Source/JavaScriptCore/runtime/JSActivation.cpp
new file mode 100644
index 000000000..83d1ee493
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSActivation.cpp
@@ -0,0 +1,244 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSActivation.h"
+
+#include "Arguments.h"
+#include "Interpreter.h"
+#include "JSFunction.h"
+
+using namespace std;
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(JSActivation);
+
+const ClassInfo JSActivation::s_info = { "JSActivation", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSActivation) };
+
+JSActivation::JSActivation(CallFrame* callFrame, FunctionExecutable* functionExecutable)
+ : Base(callFrame->globalData(), callFrame->globalData().activationStructure.get(), functionExecutable->symbolTable(), callFrame->registers())
+ , m_numCapturedArgs(max(callFrame->argumentCount(), functionExecutable->parameterCount()))
+ , m_numCapturedVars(functionExecutable->capturedVariableCount())
+ , m_requiresDynamicChecks(functionExecutable->usesEval())
+ , m_argumentsRegister(functionExecutable->generatedBytecode().argumentsRegister())
+{
+}
+
+void JSActivation::finishCreation(CallFrame* callFrame)
+{
+ Base::finishCreation(callFrame->globalData());
+ ASSERT(inherits(&s_info));
+
+ // We have to manually ref and deref the symbol table as JSVariableObject
+ // doesn't know about SharedSymbolTable
+ static_cast<SharedSymbolTable*>(m_symbolTable)->ref();
+ callFrame->globalData().heap.addFinalizer(this, &finalize);
+}
+
+void JSActivation::finalize(JSCell* cell)
+{
+ static_cast<SharedSymbolTable*>(jsCast<JSActivation*>(cell)->m_symbolTable)->deref();
+}
+
+void JSActivation::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSActivation* thisObject = jsCast<JSActivation*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ Base::visitChildren(thisObject, visitor);
+
+ // No need to mark our registers if they're still in the RegisterFile.
+ WriteBarrier<Unknown>* registerArray = thisObject->m_registerArray.get();
+ if (!registerArray)
+ return;
+
+ visitor.appendValues(registerArray, thisObject->m_numCapturedArgs);
+
+ // Skip 'this' and call frame.
+ visitor.appendValues(registerArray + CallFrame::offsetFor(thisObject->m_numCapturedArgs + 1), thisObject->m_numCapturedVars);
+}
+
+inline bool JSActivation::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
+{
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ if (entry.isNull())
+ return false;
+ if (entry.getIndex() >= m_numCapturedVars)
+ return false;
+
+ slot.setValue(registerAt(entry.getIndex()).get());
+ return true;
+}
+
+inline bool JSActivation::symbolTablePut(ExecState* exec, const Identifier& propertyName, JSValue value, bool shouldThrow)
+{
+ JSGlobalData& globalData = exec->globalData();
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ if (entry.isNull())
+ return false;
+ if (entry.isReadOnly()) {
+ if (shouldThrow)
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return true;
+ }
+ if (entry.getIndex() >= m_numCapturedVars)
+ return false;
+
+ registerAt(entry.getIndex()).set(globalData, this, value);
+ return true;
+}
+
+void JSActivation::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSActivation* thisObject = jsCast<JSActivation*>(object);
+ SymbolTable::const_iterator end = thisObject->symbolTable().end();
+ for (SymbolTable::const_iterator it = thisObject->symbolTable().begin(); it != end; ++it) {
+ if (it->second.getAttributes() & DontEnum && mode != IncludeDontEnumProperties)
+ continue;
+ if (it->second.getIndex() >= thisObject->m_numCapturedVars)
+ continue;
+ propertyNames.add(Identifier(exec, it->first.get()));
+ }
+ // Skip the JSVariableObject implementation of getOwnPropertyNames
+ JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+inline bool JSActivation::symbolTablePutWithAttributes(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+
+ SymbolTable::iterator iter = symbolTable().find(propertyName.impl());
+ if (iter == symbolTable().end())
+ return false;
+ SymbolTableEntry& entry = iter->second;
+ ASSERT(!entry.isNull());
+ if (entry.getIndex() >= m_numCapturedVars)
+ return false;
+
+ entry.setAttributes(attributes);
+ registerAt(entry.getIndex()).set(globalData, this, value);
+ return true;
+}
+
+bool JSActivation::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ JSActivation* thisObject = jsCast<JSActivation*>(cell);
+ if (propertyName == exec->propertyNames().arguments) {
+ slot.setCustom(thisObject, thisObject->getArgumentsGetter());
+ return true;
+ }
+
+ if (thisObject->symbolTableGet(propertyName, slot))
+ return true;
+
+ if (WriteBarrierBase<Unknown>* location = thisObject->getDirectLocation(exec->globalData(), propertyName)) {
+ slot.setValue(location->get());
+ return true;
+ }
+
+ // We don't call through to JSObject because there's no way to give an
+ // activation object getter properties or a prototype.
+ ASSERT(!thisObject->hasGetterSetterProperties());
+ ASSERT(thisObject->prototype().isNull());
+ return false;
+}
+
+void JSActivation::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSActivation* thisObject = jsCast<JSActivation*>(cell);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+
+ if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode()))
+ return;
+
+ // We don't call through to JSObject because __proto__ and getter/setter
+ // properties are non-standard extensions that other implementations do not
+ // expose in the activation object.
+ ASSERT(!thisObject->hasGetterSetterProperties());
+ thisObject->putDirect(exec->globalData(), propertyName, value, 0, true, slot);
+}
+
+// FIXME: Make this function honor ReadOnly (const) and DontEnum
+void JSActivation::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ JSActivation* thisObject = jsCast<JSActivation*>(object);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+
+ if (thisObject->symbolTablePutWithAttributes(exec->globalData(), 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(!thisObject->hasGetterSetterProperties());
+ JSObject::putWithAttributes(thisObject, exec, propertyName, value, attributes);
+}
+
+bool JSActivation::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
+{
+ if (propertyName == exec->propertyNames().arguments)
+ return false;
+
+ return Base::deleteProperty(cell, exec, propertyName);
+}
+
+JSObject* JSActivation::toThisObject(JSCell*, ExecState* exec)
+{
+ return exec->globalThisValue();
+}
+
+JSValue JSActivation::argumentsGetter(ExecState*, JSValue slotBase, const Identifier&)
+{
+ JSActivation* activation = asActivation(slotBase);
+ CallFrame* callFrame = CallFrame::create(reinterpret_cast<Register*>(activation->m_registers));
+ int argumentsRegister = activation->m_argumentsRegister;
+ if (JSValue arguments = callFrame->uncheckedR(argumentsRegister).jsValue())
+ return arguments;
+ int realArgumentsRegister = unmodifiedArgumentsRegister(argumentsRegister);
+
+ JSValue arguments = JSValue(Arguments::create(callFrame->globalData(), callFrame));
+ callFrame->uncheckedR(argumentsRegister) = arguments;
+ callFrame->uncheckedR(realArgumentsRegister) = arguments;
+
+ ASSERT(callFrame->uncheckedR(realArgumentsRegister).jsValue().inherits(&Arguments::s_info));
+ return callFrame->uncheckedR(realArgumentsRegister).jsValue();
+}
+
+// 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/Source/JavaScriptCore/runtime/JSActivation.h b/Source/JavaScriptCore/runtime/JSActivation.h
new file mode 100644
index 000000000..2ce053e05
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSActivation.h
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSActivation_h
+#define JSActivation_h
+
+#include "CodeBlock.h"
+#include "JSVariableObject.h"
+#include "SymbolTable.h"
+#include "Nodes.h"
+
+namespace JSC {
+
+ class Arguments;
+ class Register;
+
+ class JSActivation : public JSVariableObject {
+ private:
+ JSActivation(CallFrame*, FunctionExecutable*);
+
+ public:
+ typedef JSVariableObject Base;
+
+ static JSActivation* create(JSGlobalData& globalData, CallFrame* callFrame, FunctionExecutable* funcExec)
+ {
+ JSActivation* activation = new (NotNull, allocateCell<JSActivation>(globalData.heap)) JSActivation(callFrame, funcExec);
+ activation->finishCreation(callFrame);
+ return activation;
+ }
+
+ static void finalize(JSCell*);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ bool isDynamicScope(bool& requiresDynamicChecks) const;
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
+ static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&);
+
+ static void putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned attributes);
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
+
+ static JSObject* toThisObject(JSCell*, ExecState*);
+
+ void tearOff(JSGlobalData&);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(ActivationObjectType, StructureFlags), &s_info); }
+
+ protected:
+ void finishCreation(CallFrame*);
+ static const unsigned StructureFlags = IsEnvironmentRecord | OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
+
+ private:
+ bool symbolTableGet(const Identifier&, PropertySlot&);
+ bool symbolTableGet(const Identifier&, PropertyDescriptor&);
+ bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable);
+ bool symbolTablePut(ExecState*, const Identifier&, JSValue, bool shouldThrow);
+ bool symbolTablePutWithAttributes(JSGlobalData&, const Identifier&, JSValue, unsigned attributes);
+
+ static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&);
+ NEVER_INLINE PropertySlot::GetValueFunc getArgumentsGetter();
+
+ int m_numCapturedArgs;
+ int m_numCapturedVars : 31;
+ bool m_requiresDynamicChecks : 1;
+ int m_argumentsRegister;
+ };
+
+ JSActivation* asActivation(JSValue);
+
+ inline JSActivation* asActivation(JSValue value)
+ {
+ ASSERT(asObject(value)->inherits(&JSActivation::s_info));
+ return static_cast<JSActivation*>(asObject(value));
+ }
+
+ ALWAYS_INLINE JSActivation* Register::activation() const
+ {
+ return asActivation(jsValue());
+ }
+
+ inline bool JSActivation::isDynamicScope(bool& requiresDynamicChecks) const
+ {
+ requiresDynamicChecks = m_requiresDynamicChecks;
+ return false;
+ }
+
+ inline void JSActivation::tearOff(JSGlobalData& globalData)
+ {
+ ASSERT(!m_registerArray);
+ ASSERT(m_numCapturedVars + m_numCapturedArgs);
+
+ int registerOffset = CallFrame::offsetFor(m_numCapturedArgs + 1);
+ size_t registerArraySize = registerOffset + m_numCapturedVars;
+
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[registerArraySize]);
+ WriteBarrier<Unknown>* registers = registerArray.get() + registerOffset;
+
+ // Copy all arguments that can be captured by name or by the arguments object.
+ for (int i = 0; i < m_numCapturedArgs; ++i) {
+ int index = CallFrame::argumentOffset(i);
+ registers[index].set(globalData, this, m_registers[index].get());
+ }
+
+ // Skip 'this' and call frame.
+
+ // Copy all captured vars.
+ for (int i = 0; i < m_numCapturedVars; ++i)
+ registers[i].set(globalData, this, m_registers[i].get());
+
+ setRegisters(registers, registerArray.release());
+ }
+
+} // namespace JSC
+
+#endif // JSActivation_h
diff --git a/Source/JavaScriptCore/runtime/JSArray.cpp b/Source/JavaScriptCore/runtime/JSArray.cpp
new file mode 100644
index 000000000..da7be8564
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSArray.cpp
@@ -0,0 +1,1379 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2003 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "JSArray.h"
+
+#include "ArrayPrototype.h"
+#include "CachedCall.h"
+#include "Error.h"
+#include "Executable.h"
+#include "PropertyNameArray.h"
+#include <wtf/AVLTree.h>
+#include <wtf/Assertions.h>
+#include <wtf/OwnPtr.h>
+#include <Operations.h>
+
+using namespace std;
+using namespace WTF;
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(JSArray);
+
+// Overview of JSArray
+//
+// Properties of JSArray objects may be stored in one of three locations:
+// * The regular JSObject property map.
+// * A storage vector.
+// * A sparse map of array entries.
+//
+// Properties with non-numeric identifiers, with identifiers that are not representable
+// as an unsigned integer, or where the value is greater than MAX_ARRAY_INDEX
+// (specifically, this is only one property - the value 0xFFFFFFFFU as an unsigned 32-bit
+// integer) are not considered array indices and will be stored in the JSObject property map.
+//
+// All properties with a numeric identifer, representable as an unsigned integer i,
+// where (i <= MAX_ARRAY_INDEX), are an array index and will be stored in either the
+// storage vector or the sparse map. An array index i will be handled in the following
+// fashion:
+//
+// * Where (i < MIN_SPARSE_ARRAY_INDEX) the value will be stored in the storage vector,
+// unless the array is in SparseMode in which case all properties go into the map.
+// * 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(WriteBarrier<Unknown>)) +
+// (vectorLength * sizeof(WriteBarrier<Unknown>)) must be <= 0xFFFFFFFFU (which is maximum value of size_t).
+#define MAX_STORAGE_VECTOR_LENGTH static_cast<unsigned>((0xFFFFFFFFU - (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))) / sizeof(WriteBarrier<Unknown>))
+
+// 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
+
+// The value BASE_VECTOR_LEN is the maximum number of vector elements we'll allocate
+// for an array that was created with a sepcified length (e.g. a = new Array(123))
+#define BASE_VECTOR_LEN 4U
+
+// The upper bound to the size we'll grow a zero length array when the first element
+// is added.
+#define FIRST_VECTOR_GROW 4U
+
+// 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::s_info = {"Array", &JSNonFinalObject::s_info, 0, 0, CREATE_METHOD_TABLE(JSArray)};
+
+// We keep track of the size of the last array after it was grown. We use this
+// as a simple heuristic for as the value to grow the next array from size 0.
+// This value is capped by the constant FIRST_VECTOR_GROW defined above.
+static unsigned lastArraySize = 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(WriteBarrier<Unknown>)) + (vectorLength * sizeof(WriteBarrier<Unknown>));
+ // 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(WriteBarrier<Unknown>))) / sizeof(WriteBarrier<Unknown>) == vectorLength) && (size >= (sizeof(ArrayStorage) - sizeof(WriteBarrier<Unknown>))));
+
+ return size;
+}
+
+static inline bool isDenseEnoughForVector(unsigned length, unsigned numValues)
+{
+ return length <= MIN_SPARSE_ARRAY_INDEX || length / minDensityMultiplier <= numValues;
+}
+
+#if !CHECK_ARRAY_CONSISTENCY
+
+inline void JSArray::checkConsistency(ConsistencyCheckType)
+{
+}
+
+#endif
+
+JSArray::JSArray(JSGlobalData& globalData, Structure* structure)
+ : JSNonFinalObject(globalData, structure)
+ , m_storage(0)
+{
+}
+
+void JSArray::finishCreation(JSGlobalData& globalData, unsigned initialLength)
+{
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+
+ unsigned initialVectorLength = BASE_VECTOR_LEN;
+ unsigned initialStorageSize = storageSize(initialVectorLength);
+
+ m_storage = static_cast<ArrayStorage*>(fastMalloc(initialStorageSize));
+ m_storage->m_allocBase = m_storage;
+ m_storage->m_length = initialLength;
+ m_indexBias = 0;
+ m_vectorLength = initialVectorLength;
+ m_storage->m_sparseValueMap = 0;
+ m_storage->subclassData = 0;
+ m_storage->m_numValuesInVector = 0;
+#if CHECK_ARRAY_CONSISTENCY
+ m_storage->m_inCompactInitialization = false;
+#endif
+
+ WriteBarrier<Unknown>* vector = m_storage->m_vector;
+ for (size_t i = 0; i < initialVectorLength; ++i)
+ vector[i].clear();
+
+ checkConsistency();
+
+ Heap::heap(this)->reportExtraMemoryCost(initialStorageSize);
+}
+
+JSArray* JSArray::tryFinishCreationUninitialized(JSGlobalData& globalData, unsigned initialLength)
+{
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+
+ // Check for lengths larger than we can handle with a vector.
+ if (initialLength > MAX_STORAGE_VECTOR_LENGTH)
+ return 0;
+
+ unsigned initialVectorLength = max(initialLength, BASE_VECTOR_LEN);
+ unsigned initialStorageSize = storageSize(initialVectorLength);
+
+ m_storage = static_cast<ArrayStorage*>(fastMalloc(initialStorageSize));
+ m_storage->m_allocBase = m_storage;
+ m_storage->m_length = 0;
+ m_indexBias = 0;
+ m_vectorLength = initialVectorLength;
+ m_storage->m_sparseValueMap = 0;
+ m_storage->subclassData = 0;
+ m_storage->m_numValuesInVector = initialLength;
+#if CHECK_ARRAY_CONSISTENCY
+ m_storage->m_inCompactInitialization = true;
+#endif
+
+ WriteBarrier<Unknown>* vector = m_storage->m_vector;
+ for (size_t i = initialLength; i < initialVectorLength; ++i)
+ vector[i].clear();
+
+ Heap::heap(this)->reportExtraMemoryCost(initialStorageSize);
+ return this;
+}
+
+JSArray::~JSArray()
+{
+ ASSERT(jsCast<JSArray*>(this));
+
+ // If we are unable to allocate memory for m_storage then this may be null.
+ if (!m_storage)
+ return;
+
+ checkConsistency(DestructorConsistencyCheck);
+ delete m_storage->m_sparseValueMap;
+ fastFree(m_storage->m_allocBase);
+}
+
+void JSArray::destroy(JSCell* cell)
+{
+ jsCast<JSArray*>(cell)->JSArray::~JSArray();
+}
+
+SparseArrayValueMap::iterator SparseArrayValueMap::find(unsigned i)
+{
+ return m_map.find(i);
+}
+
+inline void SparseArrayValueMap::put(JSGlobalData& globalData, JSArray* array, unsigned i, JSValue value)
+{
+ SparseArrayEntry temp;
+ pair<Map::iterator, bool> result = m_map.add(i, temp);
+ result.first->second.set(globalData, array, value);
+ if (!result.second) // pre-existing entry
+ return;
+
+ size_t capacity = m_map.capacity();
+ if (capacity != m_reportedCapacity) {
+ Heap::heap(array)->reportExtraMemoryCost((capacity - m_reportedCapacity) * (sizeof(unsigned) + sizeof(WriteBarrier<Unknown>)));
+ m_reportedCapacity = capacity;
+ }
+}
+
+inline void SparseArrayValueMap::visitChildren(SlotVisitor& visitor)
+{
+ iterator end = m_map.end();
+ for (iterator it = m_map.begin(); it != end; ++it)
+ visitor.append(&it->second);
+}
+
+bool JSArray::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned i, PropertySlot& slot)
+{
+ JSArray* thisObject = jsCast<JSArray*>(cell);
+ ArrayStorage* storage = thisObject->m_storage;
+
+ if (i >= storage->m_length) {
+ if (i > MAX_ARRAY_INDEX)
+ return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
+ return false;
+ }
+
+ if (i < thisObject->m_vectorLength) {
+ JSValue value = storage->m_vector[i].get();
+ if (value) {
+ slot.setValue(value);
+ return true;
+ }
+ } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ SparseArrayValueMap::iterator it = map->find(i);
+ if (it != map->notFound()) {
+ slot.setValue(it->second.get());
+ return true;
+ }
+ }
+
+ return JSObject::getOwnPropertySlot(thisObject, exec, Identifier::from(exec, i), slot);
+}
+
+bool JSArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ JSArray* thisObject = jsCast<JSArray*>(cell);
+ if (propertyName == exec->propertyNames().length) {
+ slot.setValue(jsNumber(thisObject->length()));
+ return true;
+ }
+
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
+ if (isArrayIndex)
+ return JSArray::getOwnPropertySlotByIndex(thisObject, exec, i, slot);
+
+ return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+}
+
+bool JSArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ JSArray* thisObject = jsCast<JSArray*>(object);
+ if (propertyName == exec->propertyNames().length) {
+ descriptor.setDescriptor(jsNumber(thisObject->length()), DontDelete | DontEnum);
+ return true;
+ }
+
+ ArrayStorage* storage = thisObject->m_storage;
+
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
+ if (isArrayIndex) {
+ if (i >= storage->m_length)
+ return false;
+ if (i < thisObject->m_vectorLength) {
+ WriteBarrier<Unknown>& value = storage->m_vector[i];
+ if (value) {
+ descriptor.setDescriptor(value.get(), 0);
+ return true;
+ }
+ } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ SparseArrayValueMap::iterator it = map->find(i);
+ if (it != map->notFound()) {
+ descriptor.setDescriptor(it->second.get(), 0);
+ return true;
+ }
+ }
+ }
+ return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+}
+
+// ECMA 15.4.5.1
+void JSArray::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSArray* thisObject = jsCast<JSArray*>(cell);
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
+ if (isArrayIndex) {
+ putByIndex(thisObject, exec, i, value);
+ return;
+ }
+
+ if (propertyName == exec->propertyNames().length) {
+ unsigned newLength = value.toUInt32(exec);
+ if (value.toNumber(exec) != static_cast<double>(newLength)) {
+ throwError(exec, createRangeError(exec, "Invalid array length"));
+ return;
+ }
+ thisObject->setLength(newLength);
+ return;
+ }
+
+ JSObject::put(thisObject, exec, propertyName, value, slot);
+}
+
+void JSArray::putByIndex(JSCell* cell, ExecState* exec, unsigned i, JSValue value)
+{
+ JSArray* thisObject = jsCast<JSArray*>(cell);
+ thisObject->checkConsistency();
+
+ ArrayStorage* storage = thisObject->m_storage;
+
+ // Fast case - store to the vector.
+ if (i < thisObject->m_vectorLength) {
+ WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
+ unsigned length = storage->m_length;
+
+ // Update m_length & m_numValuesInVector as necessary.
+ if (i >= length) {
+ length = i + 1;
+ storage->m_length = length;
+ ++storage->m_numValuesInVector;
+ } else if (!valueSlot)
+ ++storage->m_numValuesInVector;
+
+ valueSlot.set(exec->globalData(), thisObject, value);
+ thisObject->checkConsistency();
+ return;
+ }
+
+ // Handle 2^32-1 - this is not an array index (see ES5.1 15.4), and is treated as a regular property.
+ if (UNLIKELY(i > MAX_ARRAY_INDEX)) {
+ PutPropertySlot slot;
+ thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, i), value, slot);
+ return;
+ }
+
+ // For all other cases, call putByIndexBeyondVectorLength.
+ thisObject->putByIndexBeyondVectorLength(exec->globalData(), i, value);
+ thisObject->checkConsistency();
+}
+
+NEVER_INLINE void JSArray::putByIndexBeyondVectorLength(JSGlobalData& globalData, unsigned i, JSValue value)
+{
+ // i should be a valid array index that is outside of the current vector.
+ ASSERT(i >= m_vectorLength);
+ ASSERT(i <= MAX_ARRAY_INDEX);
+
+ ArrayStorage* storage = m_storage;
+ SparseArrayValueMap* map = storage->m_sparseValueMap;
+
+ // Update m_length if necessary.
+ unsigned length = storage->m_length;
+ if (i >= length) {
+ length = i + 1;
+ storage->m_length = length;
+ }
+
+ // First, handle cases where we don't currently have a sparse map.
+ if (LIKELY(!map)) {
+ // Check that it is sensible to still be using a vector, and then try to grow the vector.
+ if (LIKELY((isDenseEnoughForVector(i, storage->m_numValuesInVector)) && increaseVectorLength(i + 1))) {
+ // success! - reread m_storage since it has likely been reallocated, and store to the vector.
+ storage = m_storage;
+ storage->m_vector[i].set(globalData, this, value);
+ ++storage->m_numValuesInVector;
+ return;
+ }
+ // We don't want to, or can't use a vector to hold this property - allocate a sparse map & add the value.
+ map = new SparseArrayValueMap;
+ storage->m_sparseValueMap = map;
+ map->put(globalData, this, i, value);
+ return;
+ }
+
+ // We are currently using a map - check whether we still want to be doing so.
+ // We will continue to use a sparse map if SparseMode is set, a vector would be too sparse, or if allocation fails.
+ unsigned numValuesInArray = storage->m_numValuesInVector + map->size();
+ if (map->sparseMode() || !isDenseEnoughForVector(length, numValuesInArray) || !increaseVectorLength(length)) {
+ map->put(globalData, this, i, value);
+ return;
+ }
+
+ // Reread m_storage afterincreaseVectorLength, update m_numValuesInVector.
+ storage = m_storage;
+ storage->m_numValuesInVector = numValuesInArray;
+
+ // Copy all values from the map into the vector, and delete the map.
+ WriteBarrier<Unknown>* vector = storage->m_vector;
+ SparseArrayValueMap::const_iterator end = map->end();
+ for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
+ vector[it->first].set(globalData, this, it->second.get());
+ delete map;
+ storage->m_sparseValueMap = 0;
+
+ // Store the new property into the vector.
+ WriteBarrier<Unknown>& valueSlot = vector[i];
+ if (!valueSlot)
+ ++storage->m_numValuesInVector;
+ valueSlot.set(globalData, this, value);
+}
+
+bool JSArray::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
+{
+ JSArray* thisObject = jsCast<JSArray*>(cell);
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(isArrayIndex);
+ if (isArrayIndex)
+ return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, i);
+
+ if (propertyName == exec->propertyNames().length)
+ return false;
+
+ return JSObject::deleteProperty(thisObject, exec, propertyName);
+}
+
+bool JSArray::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned i)
+{
+ JSArray* thisObject = jsCast<JSArray*>(cell);
+ thisObject->checkConsistency();
+
+ ArrayStorage* storage = thisObject->m_storage;
+
+ if (i < thisObject->m_vectorLength) {
+ WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
+ if (!valueSlot) {
+ thisObject->checkConsistency();
+ return false;
+ }
+ valueSlot.clear();
+ --storage->m_numValuesInVector;
+ thisObject->checkConsistency();
+ return true;
+ }
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ SparseArrayValueMap::iterator it = map->find(i);
+ if (it != map->notFound()) {
+ map->remove(it);
+ thisObject->checkConsistency();
+ return true;
+ }
+ }
+
+ thisObject->checkConsistency();
+
+ if (i > MAX_ARRAY_INDEX)
+ return thisObject->methodTable()->deleteProperty(thisObject, exec, Identifier::from(exec, i));
+
+ return false;
+}
+
+void JSArray::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSArray* thisObject = jsCast<JSArray*>(object);
+ // 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 = thisObject->m_storage;
+
+ unsigned usedVectorLength = min(storage->m_length, thisObject->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::const_iterator end = map->end();
+ for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
+ propertyNames.add(Identifier::from(exec, it->first));
+ }
+
+ if (mode == IncludeDontEnumProperties)
+ propertyNames.add(exec->propertyNames().length);
+
+ JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+ALWAYS_INLINE unsigned JSArray::getNewVectorLength(unsigned desiredLength)
+{
+ ASSERT(desiredLength <= MAX_STORAGE_VECTOR_LENGTH);
+
+ unsigned increasedLength;
+ unsigned maxInitLength = min(m_storage->m_length, 100000U);
+
+ if (desiredLength < maxInitLength)
+ increasedLength = maxInitLength;
+ else if (!m_vectorLength)
+ increasedLength = max(desiredLength, lastArraySize);
+ else {
+ // Mathematically equivalent to:
+ // increasedLength = (newLength * 3 + 1) / 2;
+ // or:
+ // increasedLength = (unsigned)ceil(newLength * 1.5));
+ // This form is not prone to internal overflow.
+ increasedLength = desiredLength + (desiredLength >> 1) + (desiredLength & 1);
+ }
+
+ ASSERT(increasedLength >= desiredLength);
+
+ lastArraySize = min(increasedLength, FIRST_VECTOR_GROW);
+
+ return min(increasedLength, MAX_STORAGE_VECTOR_LENGTH);
+}
+
+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.
+ if (newLength > MAX_STORAGE_VECTOR_LENGTH)
+ return false;
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned vectorLength = m_vectorLength;
+ ASSERT(newLength > vectorLength);
+ unsigned newVectorLength = getNewVectorLength(newLength);
+ void* baseStorage = storage->m_allocBase;
+
+ // Fast case - there is no precapacity. In these cases a realloc makes sense.
+ if (LIKELY(!m_indexBias)) {
+ if (!tryFastRealloc(baseStorage, storageSize(newVectorLength)).getValue(baseStorage))
+ return false;
+
+ storage = m_storage = reinterpret_cast_ptr<ArrayStorage*>(baseStorage);
+ m_storage->m_allocBase = baseStorage;
+
+ WriteBarrier<Unknown>* vector = storage->m_vector;
+ for (unsigned i = vectorLength; i < newVectorLength; ++i)
+ vector[i].clear();
+
+ m_vectorLength = newVectorLength;
+
+ Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength));
+ return true;
+ }
+
+ // Remove some, but not all of the precapacity. Atomic decay, & capped to not overflow array length.
+ unsigned newIndexBias = min(m_indexBias >> 1, MAX_STORAGE_VECTOR_LENGTH - newVectorLength);
+ // Calculate new stoarge capcity, allowing room for the pre-capacity.
+ unsigned newStorageCapacity = newVectorLength + newIndexBias;
+ void* newAllocBase;
+ if (!tryFastMalloc(storageSize(newStorageCapacity)).getValue(newAllocBase))
+ return false;
+ // The sum of m_vectorLength and m_indexBias will never exceed MAX_STORAGE_VECTOR_LENGTH.
+ ASSERT(m_vectorLength <= MAX_STORAGE_VECTOR_LENGTH && (MAX_STORAGE_VECTOR_LENGTH - m_vectorLength) >= m_indexBias);
+ unsigned currentCapacity = m_vectorLength + m_indexBias;
+ // Currently there is no way to report to the heap that the extra capacity is shrinking!
+ if (newStorageCapacity > currentCapacity)
+ Heap::heap(this)->reportExtraMemoryCost((newStorageCapacity - currentCapacity) * sizeof(WriteBarrier<Unknown>));
+
+ m_vectorLength = newVectorLength;
+ m_indexBias = newIndexBias;
+ m_storage = reinterpret_cast_ptr<ArrayStorage*>(reinterpret_cast<WriteBarrier<Unknown>*>(newAllocBase) + m_indexBias);
+
+ // Copy the ArrayStorage header & current contents of the vector, clear the new post-capacity.
+ memmove(m_storage, storage, storageSize(vectorLength));
+ for (unsigned i = vectorLength; i < m_vectorLength; ++i)
+ m_storage->m_vector[i].clear();
+
+ // Free the old allocation, update m_allocBase.
+ fastFree(m_storage->m_allocBase);
+ m_storage->m_allocBase = newAllocBase;
+
+ return true;
+}
+
+// This method makes room in the vector, but leaves the new space uncleared.
+bool JSArray::unshiftCountSlowCase(unsigned count)
+{
+ // If not, we should have handled this on the fast path.
+ ASSERT(count > m_indexBias);
+
+ ArrayStorage* storage = m_storage;
+
+ // Step 1:
+ // Gather 4 key metrics:
+ // * usedVectorLength - how many entries are currently in the vector (conservative estimate - fewer may be in use in sparse vectors).
+ // * requiredVectorLength - how many entries are will there be in the vector, after allocating space for 'count' more.
+ // * currentCapacity - what is the current size of the vector, including any pre-capacity.
+ // * desiredCapacity - how large should we like to grow the vector to - based on 2x requiredVectorLength.
+
+ unsigned length = storage->m_length;
+ unsigned usedVectorLength = min(m_vectorLength, length);
+ ASSERT(usedVectorLength <= MAX_STORAGE_VECTOR_LENGTH);
+ // Check that required vector length is possible, in an overflow-safe fashion.
+ if (count > MAX_STORAGE_VECTOR_LENGTH - usedVectorLength)
+ return false;
+ unsigned requiredVectorLength = usedVectorLength + count;
+ ASSERT(requiredVectorLength <= MAX_STORAGE_VECTOR_LENGTH);
+ // The sum of m_vectorLength and m_indexBias will never exceed MAX_STORAGE_VECTOR_LENGTH.
+ ASSERT(m_vectorLength <= MAX_STORAGE_VECTOR_LENGTH && (MAX_STORAGE_VECTOR_LENGTH - m_vectorLength) >= m_indexBias);
+ unsigned currentCapacity = m_vectorLength + m_indexBias;
+ // The calculation of desiredCapacity won't overflow, due to the range of MAX_STORAGE_VECTOR_LENGTH.
+ unsigned desiredCapacity = min(MAX_STORAGE_VECTOR_LENGTH, max(BASE_VECTOR_LEN, requiredVectorLength) << 1);
+
+ // Step 2:
+ // We're either going to choose to allocate a new ArrayStorage, or we're going to reuse the existing on.
+
+ void* newAllocBase;
+ unsigned newStorageCapacity;
+ // If the current storage array is sufficiently large (but not too large!) then just keep using it.
+ if (currentCapacity > desiredCapacity && isDenseEnoughForVector(currentCapacity, requiredVectorLength)) {
+ newAllocBase = storage->m_allocBase;
+ newStorageCapacity = currentCapacity;
+ } else {
+ if (!tryFastMalloc(storageSize(desiredCapacity)).getValue(newAllocBase))
+ return false;
+ newStorageCapacity = desiredCapacity;
+ // Currently there is no way to report to the heap that the extra capacity is shrinking!
+ if (desiredCapacity > currentCapacity)
+ Heap::heap(this)->reportExtraMemoryCost((desiredCapacity - currentCapacity) * sizeof(WriteBarrier<Unknown>));
+ }
+
+ // Step 3:
+ // Work out where we're going to move things to.
+
+ // Determine how much of the vector to use as pre-capacity, and how much as post-capacity.
+ // If the vector had no free post-capacity (length >= m_vectorLength), don't give it any.
+ // If it did, we calculate the amount that will remain based on an atomic decay - leave the
+ // vector with half the post-capacity it had previously.
+ unsigned postCapacity = 0;
+ if (length < m_vectorLength) {
+ // Atomic decay, + the post-capacity cannot be greater than what is available.
+ postCapacity = min((m_vectorLength - length) >> 1, newStorageCapacity - requiredVectorLength);
+ // If we're moving contents within the same allocation, the post-capacity is being reduced.
+ ASSERT(newAllocBase != storage->m_allocBase || postCapacity < m_vectorLength - length);
+ }
+
+ m_vectorLength = requiredVectorLength + postCapacity;
+ m_indexBias = newStorageCapacity - m_vectorLength;
+ m_storage = reinterpret_cast_ptr<ArrayStorage*>(reinterpret_cast<WriteBarrier<Unknown>*>(newAllocBase) + m_indexBias);
+
+ // Step 4:
+ // Copy array data / header into their new locations, clear post-capacity & free any old allocation.
+
+ // If this is being moved within the existing buffer of memory, we are always shifting data
+ // to the right (since count > m_indexBias). As such this memmove cannot trample the header.
+ memmove(m_storage->m_vector + count, storage->m_vector, sizeof(WriteBarrier<Unknown>) * usedVectorLength);
+ memmove(m_storage, storage, storageSize(0));
+
+ // Are we copying into a new allocation?
+ if (newAllocBase != m_storage->m_allocBase) {
+ // Free the old allocation, update m_allocBase.
+ fastFree(m_storage->m_allocBase);
+ m_storage->m_allocBase = newAllocBase;
+
+ // We need to clear any entries in the vector beyond length. We only need to
+ // do this if this was a new allocation, because if we're using an existing
+ // allocation the post-capacity will already be cleared, and in an existing
+ // allocation we can only beshrinking the amount of post capacity.
+ for (unsigned i = requiredVectorLength; i < m_vectorLength; ++i)
+ m_storage->m_vector[i].clear();
+ }
+
+ return true;
+}
+
+void JSArray::setLength(unsigned newLength)
+{
+ checkConsistency();
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned length = storage->m_length;
+
+ if (newLength < length) {
+ unsigned usedVectorLength = min(length, m_vectorLength);
+ for (unsigned i = newLength; i < usedVectorLength; ++i) {
+ WriteBarrier<Unknown>& valueSlot = storage->m_vector[i];
+ bool hadValue = valueSlot;
+ valueSlot.clear();
+ storage->m_numValuesInVector -= hadValue;
+ }
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ SparseArrayValueMap copy = *map;
+ SparseArrayValueMap::const_iterator end = copy.end();
+ for (SparseArrayValueMap::const_iterator it = copy.begin(); it != end; ++it) {
+ if (it->first >= newLength)
+ map->remove(it->first);
+ }
+ if (map->isEmpty() && !map->sparseMode()) {
+ delete map;
+ storage->m_sparseValueMap = 0;
+ }
+ }
+ }
+
+ storage->m_length = newLength;
+
+ checkConsistency();
+}
+
+JSValue JSArray::pop()
+{
+ checkConsistency();
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned length = storage->m_length;
+ if (!length)
+ return jsUndefined();
+
+ --length;
+
+ JSValue result;
+
+ if (length < m_vectorLength) {
+ WriteBarrier<Unknown>& valueSlot = storage->m_vector[length];
+ if (valueSlot) {
+ --storage->m_numValuesInVector;
+ result = valueSlot.get();
+ valueSlot.clear();
+ } else
+ result = jsUndefined();
+ } else {
+ result = jsUndefined();
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ SparseArrayValueMap::iterator it = map->find(length);
+ if (it != map->end()) {
+ result = it->second.get();
+ map->remove(it);
+ if (map->isEmpty() && !map->sparseMode()) {
+ delete map;
+ storage->m_sparseValueMap = 0;
+ }
+ }
+ }
+ }
+
+ storage->m_length = length;
+
+ checkConsistency();
+
+ return result;
+}
+
+// Push & putIndex are almost identical, with two small differences.
+// - we always are writing beyond the current array bounds, so it is always necessary to update m_length & m_numValuesInVector.
+// - pushing to an array of length 2^32-1 stores the property, but throws a range error.
+void JSArray::push(ExecState* exec, JSValue value)
+{
+ checkConsistency();
+ ArrayStorage* storage = m_storage;
+
+ // Fast case - push within vector, always update m_length & m_numValuesInVector.
+ unsigned length = storage->m_length;
+ if (length < m_vectorLength) {
+ storage->m_vector[length].set(exec->globalData(), this, value);
+ storage->m_length = length + 1;
+ ++storage->m_numValuesInVector;
+ checkConsistency();
+ return;
+ }
+
+ // Pushing to an array of length 2^32-1 stores the property, but throws a range error.
+ if (UNLIKELY(storage->m_length == 0xFFFFFFFFu)) {
+ methodTable()->putByIndex(this, exec, storage->m_length, value);
+ // Per ES5.1 15.4.4.7 step 6 & 15.4.5.1 step 3.d.
+ throwError(exec, createRangeError(exec, "Invalid array length"));
+ return;
+ }
+
+ // Handled the same as putIndex.
+ putByIndexBeyondVectorLength(exec->globalData(), storage->m_length, value);
+ checkConsistency();
+}
+
+void JSArray::shiftCount(ExecState* exec, unsigned count)
+{
+ ASSERT(count > 0);
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned oldLength = storage->m_length;
+
+ if (!oldLength)
+ return;
+
+ if (oldLength != storage->m_numValuesInVector) {
+ // If m_length and m_numValuesInVector aren't the same, we have a sparse vector
+ // which means we need to go through each entry looking for the the "empty"
+ // slots and then fill them with possible properties. See ECMA spec.
+ // 15.4.4.9 steps 11 through 13.
+ for (unsigned i = count; i < oldLength; ++i) {
+ if ((i >= m_vectorLength) || (!m_storage->m_vector[i])) {
+ PropertySlot slot(this);
+ JSValue p = prototype();
+ if ((!p.isNull()) && (asObject(p)->getPropertySlot(exec, i, slot)))
+ methodTable()->putByIndex(this, exec, i, slot.getValue(exec, i));
+ }
+ }
+
+ storage = m_storage; // The put() above could have grown the vector and realloc'ed storage.
+
+ // Need to decrement numValuesInvector based on number of real entries
+ for (unsigned i = 0; i < (unsigned)count; ++i)
+ if ((i < m_vectorLength) && (storage->m_vector[i]))
+ --storage->m_numValuesInVector;
+ } else
+ storage->m_numValuesInVector -= count;
+
+ storage->m_length -= count;
+
+ if (m_vectorLength) {
+ count = min(m_vectorLength, (unsigned)count);
+
+ m_vectorLength -= count;
+
+ if (m_vectorLength) {
+ char* newBaseStorage = reinterpret_cast<char*>(storage) + count * sizeof(WriteBarrier<Unknown>);
+ memmove(newBaseStorage, storage, storageSize(0));
+ m_storage = reinterpret_cast_ptr<ArrayStorage*>(newBaseStorage);
+
+ m_indexBias += count;
+ }
+ }
+}
+
+void JSArray::unshiftCount(ExecState* exec, unsigned count)
+{
+ ArrayStorage* storage = m_storage;
+ unsigned length = storage->m_length;
+
+ if (length != storage->m_numValuesInVector) {
+ // If m_length and m_numValuesInVector aren't the same, we have a sparse vector
+ // which means we need to go through each entry looking for the the "empty"
+ // slots and then fill them with possible properties. See ECMA spec.
+ // 15.4.4.13 steps 8 through 10.
+ for (unsigned i = 0; i < length; ++i) {
+ if ((i >= m_vectorLength) || (!m_storage->m_vector[i])) {
+ PropertySlot slot(this);
+ JSValue p = prototype();
+ if ((!p.isNull()) && (asObject(p)->getPropertySlot(exec, i, slot)))
+ methodTable()->putByIndex(this, exec, i, slot.getValue(exec, i));
+ }
+ }
+ }
+
+ storage = m_storage; // The put() above could have grown the vector and realloc'ed storage.
+
+ if (m_indexBias >= count) {
+ m_indexBias -= count;
+ char* newBaseStorage = reinterpret_cast<char*>(storage) - count * sizeof(WriteBarrier<Unknown>);
+ memmove(newBaseStorage, storage, storageSize(0));
+ m_storage = reinterpret_cast_ptr<ArrayStorage*>(newBaseStorage);
+ m_vectorLength += count;
+ } else if (!unshiftCountSlowCase(count)) {
+ throwOutOfMemoryError(exec);
+ return;
+ }
+
+ WriteBarrier<Unknown>* vector = m_storage->m_vector;
+ for (unsigned i = 0; i < count; i++)
+ vector[i].clear();
+}
+
+void JSArray::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSArray* thisObject = jsCast<JSArray*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+
+ JSNonFinalObject::visitChildren(thisObject, visitor);
+
+ ArrayStorage* storage = thisObject->m_storage;
+
+ unsigned usedVectorLength = std::min(storage->m_length, thisObject->m_vectorLength);
+ visitor.appendValues(storage->m_vector, usedVectorLength);
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap)
+ map->visitChildren(visitor);
+}
+
+static int compareNumbersForQSort(const void* a, const void* b)
+{
+ double da = static_cast<const JSValue*>(a)->asNumber();
+ double db = static_cast<const JSValue*>(b)->asNumber();
+ return (da > db) - (da < db);
+}
+
+static int compareByStringPairForQSort(const void* a, const void* b)
+{
+ const ValueStringPair* va = static_cast<const ValueStringPair*>(a);
+ const ValueStringPair* vb = static_cast<const ValueStringPair*>(b);
+ return codePointCompare(va->second, vb->second);
+}
+
+void JSArray::sortNumeric(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
+{
+ ASSERT(!inSparseMode());
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned lengthNotIncludingUndefined = compactForSorting();
+ if (storage->m_sparseValueMap) {
+ throwOutOfMemoryError(exec);
+ return;
+ }
+
+ if (!lengthNotIncludingUndefined)
+ return;
+
+ bool allValuesAreNumbers = true;
+ size_t size = storage->m_numValuesInVector;
+ for (size_t i = 0; i < size; ++i) {
+ if (!storage->m_vector[i].isNumber()) {
+ allValuesAreNumbers = false;
+ break;
+ }
+ }
+
+ if (!allValuesAreNumbers)
+ return sort(exec, compareFunction, callType, callData);
+
+ // For numeric comparison, which is fast, qsort is faster than mergesort. We
+ // also don't require mergesort's stability, since there's no user visible
+ // side-effect from swapping the order of equal primitive values.
+ qsort(storage->m_vector, size, sizeof(WriteBarrier<Unknown>), compareNumbersForQSort);
+
+ checkConsistency(SortConsistencyCheck);
+}
+
+void JSArray::sort(ExecState* exec)
+{
+ ASSERT(!inSparseMode());
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned lengthNotIncludingUndefined = compactForSorting();
+ if (storage->m_sparseValueMap) {
+ throwOutOfMemoryError(exec);
+ return;
+ }
+
+ if (!lengthNotIncludingUndefined)
+ return;
+
+ // Converting JavaScript values to strings can be expensive, so we do it once up front and sort based on that.
+ // This is a considerable improvement over doing it twice per comparison, though it requires a large temporary
+ // buffer. Besides, this protects us from crashing if some objects have custom toString methods that return
+ // random or otherwise changing results, effectively making compare function inconsistent.
+
+ Vector<ValueStringPair> values(lengthNotIncludingUndefined);
+ if (!values.begin()) {
+ throwOutOfMemoryError(exec);
+ return;
+ }
+
+ Heap::heap(this)->pushTempSortVector(&values);
+
+ for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
+ JSValue value = storage->m_vector[i].get();
+ ASSERT(!value.isUndefined());
+ values[i].first = value;
+ }
+
+ // 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()) {
+ Heap::heap(this)->popTempSortVector(&values);
+ return;
+ }
+
+ // FIXME: Since we sort by string value, a fast algorithm might be to use a radix sort. That would be O(N) rather
+ // than O(N log N).
+
+#if HAVE(MERGESORT)
+ mergesort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+#else
+ // FIXME: The qsort library function is likely to not be a stable sort.
+ // ECMAScript-262 does not specify a stable sort, but in practice, browsers perform a stable sort.
+ qsort(values.begin(), values.size(), sizeof(ValueStringPair), compareByStringPairForQSort);
+#endif
+
+ // If the toString function changed the length of the array or vector storage,
+ // increase the length to handle the orignal number of actual values.
+ if (m_vectorLength < lengthNotIncludingUndefined)
+ increaseVectorLength(lengthNotIncludingUndefined);
+ if (storage->m_length < lengthNotIncludingUndefined)
+ storage->m_length = lengthNotIncludingUndefined;
+
+ JSGlobalData& globalData = exec->globalData();
+ for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
+ storage->m_vector[i].set(globalData, this, values[i].first);
+
+ Heap::heap(this)->popTempSortVector(&values);
+
+ 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;
+ OwnPtr<CachedCall> m_cachedCall;
+
+ handle get_less(handle h) { return m_nodes[h].lt & 0x7FFFFFFF; }
+ void set_less(handle h, handle lh) { m_nodes[h].lt &= 0x80000000; m_nodes[h].lt |= lh; }
+ handle get_greater(handle h) { return m_nodes[h].gt & 0x7FFFFFFF; }
+ void set_greater(handle h, handle gh) { m_nodes[h].gt &= 0x80000000; m_nodes[h].gt |= gh; }
+
+ int get_balance_factor(handle h)
+ {
+ if (m_nodes[h].gt & 0x80000000)
+ return -1;
+ return static_cast<unsigned>(m_nodes[h].lt) >> 31;
+ }
+
+ void set_balance_factor(handle h, int bf)
+ {
+ if (bf == 0) {
+ m_nodes[h].lt &= 0x7FFFFFFF;
+ m_nodes[h].gt &= 0x7FFFFFFF;
+ } else {
+ m_nodes[h].lt |= 0x80000000;
+ if (bf < 0)
+ m_nodes[h].gt |= 0x80000000;
+ else
+ m_nodes[h].gt &= 0x7FFFFFFF;
+ }
+ }
+
+ int compare_key_key(key va, key vb)
+ {
+ ASSERT(!va.isUndefined());
+ ASSERT(!vb.isUndefined());
+
+ if (m_exec->hadException())
+ return 1;
+
+ double compareResult;
+ if (m_cachedCall) {
+ m_cachedCall->setThis(jsUndefined());
+ m_cachedCall->setArgument(0, va);
+ m_cachedCall->setArgument(1, vb);
+ compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame(m_exec));
+ } else {
+ MarkedArgumentBuffer arguments;
+ arguments.append(va);
+ arguments.append(vb);
+ compareResult = call(m_exec, m_compareFunction, m_compareCallType, *m_compareCallData, jsUndefined(), arguments).toNumber(m_exec);
+ }
+ return (compareResult < 0) ? -1 : 1; // Not passing equality through, because we need to store all values, even if equivalent.
+ }
+
+ int compare_key_node(key k, handle h) { return compare_key_key(k, m_nodes[h].value); }
+ int compare_node_node(handle h1, handle h2) { return compare_key_key(m_nodes[h1].value, m_nodes[h2].value); }
+
+ static handle null() { return 0x7FFFFFFF; }
+};
+
+void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, const CallData& callData)
+{
+ ASSERT(!inSparseMode());
+
+ checkConsistency();
+
+ ArrayStorage* storage = m_storage;
+
+ // 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(storage->m_length <= static_cast<unsigned>(std::numeric_limits<int>::max()));
+ if (storage->m_length > static_cast<unsigned>(std::numeric_limits<int>::max()))
+ return;
+
+ unsigned usedVectorLength = min(storage->m_length, m_vectorLength);
+ unsigned nodeCount = usedVectorLength + (storage->m_sparseValueMap ? storage->m_sparseValueMap->size() : 0);
+
+ if (!nodeCount)
+ return;
+
+ AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items
+ tree.abstractor().m_exec = exec;
+ tree.abstractor().m_compareFunction = compareFunction;
+ tree.abstractor().m_compareCallType = callType;
+ tree.abstractor().m_compareCallData = &callData;
+ tree.abstractor().m_nodes.grow(nodeCount);
+
+ if (callType == CallTypeJS)
+ tree.abstractor().m_cachedCall = adoptPtr(new CachedCall(exec, asFunction(compareFunction), 2));
+
+ if (!tree.abstractor().m_nodes.begin()) {
+ throwOutOfMemoryError(exec);
+ return;
+ }
+
+ // FIXME: If the compare function modifies the array, the vector, map, etc. could be modified
+ // right out from under us while we're building the tree here.
+
+ unsigned numDefined = 0;
+ unsigned numUndefined = 0;
+
+ // Iterate over the array, ignoring missing values, counting undefined ones, and inserting all other ones into the tree.
+ for (; numDefined < usedVectorLength; ++numDefined) {
+ JSValue v = storage->m_vector[numDefined].get();
+ if (!v || v.isUndefined())
+ break;
+ tree.abstractor().m_nodes[numDefined].value = v;
+ tree.insert(numDefined);
+ }
+ for (unsigned i = numDefined; i < usedVectorLength; ++i) {
+ JSValue v = storage->m_vector[i].get();
+ if (v) {
+ if (v.isUndefined())
+ ++numUndefined;
+ else {
+ tree.abstractor().m_nodes[numDefined].value = v;
+ tree.insert(numDefined);
+ ++numDefined;
+ }
+ }
+ }
+
+ unsigned newUsedVectorLength = numDefined + numUndefined;
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ newUsedVectorLength += map->size();
+ if (newUsedVectorLength > 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;
+ }
+ }
+
+ storage = m_storage;
+
+ SparseArrayValueMap::const_iterator end = map->end();
+ for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it) {
+ tree.abstractor().m_nodes[numDefined].value = it->second.get();
+ tree.insert(numDefined);
+ ++numDefined;
+ }
+
+ delete map;
+ 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);
+ JSGlobalData& globalData = exec->globalData();
+ for (unsigned i = 0; i < numDefined; ++i) {
+ storage->m_vector[i].set(globalData, this, tree.abstractor().m_nodes[*iter].value);
+ ++iter;
+ }
+
+ // Put undefined values back in.
+ for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
+ storage->m_vector[i].setUndefined();
+
+ // Ensure that unused values in the vector are zeroed out.
+ for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
+ storage->m_vector[i].clear();
+
+ storage->m_numValuesInVector = newUsedVectorLength;
+
+ checkConsistency(SortConsistencyCheck);
+}
+
+void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args)
+{
+ ArrayStorage* storage = m_storage;
+
+ WriteBarrier<Unknown>* vector = storage->m_vector;
+ unsigned vectorEnd = min(storage->m_length, m_vectorLength);
+ unsigned i = 0;
+ for (; i < vectorEnd; ++i) {
+ WriteBarrier<Unknown>& v = vector[i];
+ if (!v)
+ break;
+ args.append(v.get());
+ }
+
+ for (; i < storage->m_length; ++i)
+ args.append(get(exec, i));
+}
+
+void JSArray::copyToArguments(ExecState* exec, CallFrame* callFrame, uint32_t length)
+{
+ ASSERT(length == this->length());
+ UNUSED_PARAM(length);
+ unsigned i = 0;
+ WriteBarrier<Unknown>* vector = m_storage->m_vector;
+ unsigned vectorEnd = min(length, m_vectorLength);
+ for (; i < vectorEnd; ++i) {
+ WriteBarrier<Unknown>& v = vector[i];
+ if (!v)
+ break;
+ callFrame->setArgument(i, v.get());
+ }
+
+ for (; i < length; ++i)
+ callFrame->setArgument(i, get(exec, i));
+}
+
+unsigned JSArray::compactForSorting()
+{
+ ASSERT(!inSparseMode());
+
+ checkConsistency();
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned usedVectorLength = min(storage->m_length, m_vectorLength);
+
+ unsigned numDefined = 0;
+ unsigned numUndefined = 0;
+
+ for (; numDefined < usedVectorLength; ++numDefined) {
+ JSValue v = storage->m_vector[numDefined].get();
+ if (!v || v.isUndefined())
+ break;
+ }
+
+ for (unsigned i = numDefined; i < usedVectorLength; ++i) {
+ JSValue v = storage->m_vector[i].get();
+ if (v) {
+ if (v.isUndefined())
+ ++numUndefined;
+ else
+ storage->m_vector[numDefined++].setWithoutWriteBarrier(v);
+ }
+ }
+
+ unsigned newUsedVectorLength = numDefined + numUndefined;
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ newUsedVectorLength += map->size();
+ if (newUsedVectorLength > 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::const_iterator end = map->end();
+ for (SparseArrayValueMap::const_iterator it = map->begin(); it != end; ++it)
+ storage->m_vector[numDefined++].setWithoutWriteBarrier(it->second.get());
+
+ delete map;
+ storage->m_sparseValueMap = 0;
+ }
+
+ for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
+ storage->m_vector[i].setUndefined();
+ for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
+ storage->m_vector[i].clear();
+
+ storage->m_numValuesInVector = newUsedVectorLength;
+
+ checkConsistency(SortConsistencyCheck);
+
+ return numDefined;
+}
+
+void* JSArray::subclassData() const
+{
+ return m_storage->subclassData;
+}
+
+void JSArray::setSubclassData(void* d)
+{
+ m_storage->subclassData = d;
+}
+
+#if CHECK_ARRAY_CONSISTENCY
+
+void JSArray::checkConsistency(ConsistencyCheckType type)
+{
+ ArrayStorage* storage = m_storage;
+
+ ASSERT(!storage->m_inCompactInitialization);
+
+ ASSERT(storage);
+ if (type == SortConsistencyCheck)
+ ASSERT(!storage->m_sparseValueMap);
+
+ unsigned numValuesInVector = 0;
+ for (unsigned i = 0; i < m_vectorLength; ++i) {
+ if (JSValue value = storage->m_vector[i]) {
+ ASSERT(i < storage->m_length);
+ if (type != DestructorConsistencyCheck)
+ value.isUndefined(); // Likely to crash if the object was deallocated.
+ ++numValuesInVector;
+ } else {
+ if (type == SortConsistencyCheck)
+ ASSERT(i >= storage->m_numValuesInVector);
+ }
+ }
+ ASSERT(numValuesInVector == storage->m_numValuesInVector);
+ ASSERT(numValuesInVector <= storage->m_length);
+
+ if (storage->m_sparseValueMap) {
+ SparseArrayValueMap::iterator end = storage->m_sparseValueMap->end();
+ for (SparseArrayValueMap::iterator it = storage->m_sparseValueMap->begin(); it != end; ++it) {
+ unsigned index = it->first;
+ ASSERT(index < storage->m_length);
+ ASSERT(index >= storage->m_vectorLength);
+ ASSERT(index <= MAX_ARRAY_INDEX);
+ ASSERT(it->second);
+ if (type != DestructorConsistencyCheck)
+ it->second.isUndefined(); // Likely to crash if the object was deallocated.
+ }
+ }
+}
+
+#endif
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSArray.h b/Source/JavaScriptCore/runtime/JSArray.h
new file mode 100644
index 000000000..9102c8724
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSArray.h
@@ -0,0 +1,293 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef JSArray_h
+#define JSArray_h
+
+#include "JSObject.h"
+
+#define CHECK_ARRAY_CONSISTENCY 0
+
+namespace JSC {
+
+ class JSArray;
+
+ struct SparseArrayEntry : public WriteBarrier<Unknown> {
+ SparseArrayEntry() : attributes(0) {}
+ unsigned attributes;
+ };
+
+ class SparseArrayValueMap {
+ typedef HashMap<unsigned, SparseArrayEntry> Map;
+
+ enum Flags {
+ Normal = 0,
+ SparseMode = 1
+ };
+
+ public:
+ typedef Map::iterator iterator;
+ typedef Map::const_iterator const_iterator;
+
+ SparseArrayValueMap()
+ : m_flags(Normal)
+ , m_reportedCapacity(0)
+ {
+ }
+
+ void visitChildren(SlotVisitor&);
+
+ bool sparseMode()
+ {
+ return m_flags & SparseMode;
+ }
+
+ void setSparseMode()
+ {
+ m_flags = (Flags)(m_flags | SparseMode);
+ }
+
+ // These methods may mutate the contents of the map
+ void put(JSGlobalData&, JSArray*, unsigned, JSValue);
+ iterator find(unsigned);
+ // This should ASSERT the remove is valid (check the result of the find).
+ void remove(iterator it) { m_map.remove(it); }
+ void remove(unsigned i) { m_map.remove(i); }
+
+ // These methods do not mutate the contents of the map.
+ iterator notFound() { return m_map.end(); }
+ bool isEmpty() const { return m_map.isEmpty(); }
+ bool contains(unsigned i) const { return m_map.contains(i); }
+ size_t size() const { return m_map.size(); }
+ // Only allow const begin/end iteration.
+ const_iterator begin() const { return m_map.begin(); }
+ const_iterator end() const { return m_map.end(); }
+
+ private:
+ Map m_map;
+ Flags m_flags;
+ size_t m_reportedCapacity;
+ };
+
+ // This struct holds the actual data values of an array. A JSArray object points to it's contained ArrayStorage
+ // struct by pointing to m_vector. To access the contained ArrayStorage struct, use the getStorage() and
+ // setStorage() methods. It is important to note that there may be space before the ArrayStorage that
+ // is used to quick unshift / shift operation. The actual allocated pointer is available by using:
+ // getStorage() - m_indexBias * sizeof(JSValue)
+ struct ArrayStorage {
+ unsigned m_length; // The "length" property on the array
+ unsigned m_numValuesInVector;
+ SparseArrayValueMap* m_sparseValueMap;
+ void* subclassData; // A JSArray subclass can use this to fill the vector lazily.
+ void* m_allocBase; // Pointer to base address returned by malloc(). Keeping this pointer does eliminate false positives from the leak detector.
+#if CHECK_ARRAY_CONSISTENCY
+ bool m_inCompactInitialization;
+#endif
+ WriteBarrier<Unknown> m_vector[1];
+ };
+
+ class JSArray : public JSNonFinalObject {
+ friend class Walker;
+
+ protected:
+ explicit JSArray(JSGlobalData&, Structure*);
+
+ void finishCreation(JSGlobalData&, unsigned initialLength = 0);
+ JSArray* tryFinishCreationUninitialized(JSGlobalData&, unsigned initialLength);
+
+ public:
+ typedef JSNonFinalObject Base;
+
+ ~JSArray();
+ static void destroy(JSCell*);
+
+ static JSArray* create(JSGlobalData& globalData, Structure* structure, unsigned initialLength = 0)
+ {
+ JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure);
+ array->finishCreation(globalData, initialLength);
+ return array;
+ }
+
+ // tryCreateUninitialized is used for fast construction of arrays whose size and
+ // contents are known at time of creation. Clients of this interface must:
+ // - null-check the result (indicating out of memory, or otherwise unable to allocate vector).
+ // - call 'initializeIndex' for all properties in sequence, for 0 <= i < initialLength.
+ // - called 'completeInitialization' after all properties have been initialized.
+ static JSArray* tryCreateUninitialized(JSGlobalData& globalData, Structure* structure, unsigned initialLength)
+ {
+ JSArray* array = new (NotNull, allocateCell<JSArray>(globalData.heap)) JSArray(globalData, structure);
+ return array->tryFinishCreationUninitialized(globalData, initialLength);
+ }
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue);
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ unsigned length() const { return m_storage->m_length; }
+ void setLength(unsigned); // OK to use on new arrays, but not if it might be a RegExpMatchArray.
+
+ void sort(ExecState*);
+ void sort(ExecState*, JSValue compareFunction, CallType, const CallData&);
+ void sortNumeric(ExecState*, JSValue compareFunction, CallType, const CallData&);
+
+ void push(ExecState*, JSValue);
+ JSValue pop();
+
+ void shiftCount(ExecState*, unsigned count);
+ void unshiftCount(ExecState*, unsigned count);
+
+ bool canGetIndex(unsigned i) { return i < m_vectorLength && m_storage->m_vector[i]; }
+ JSValue getIndex(unsigned i)
+ {
+ ASSERT(canGetIndex(i));
+ return m_storage->m_vector[i].get();
+ }
+
+ bool canSetIndex(unsigned i) { return i < m_vectorLength; }
+ void setIndex(JSGlobalData& globalData, unsigned i, JSValue v)
+ {
+ ASSERT(canSetIndex(i));
+
+ WriteBarrier<Unknown>& x = m_storage->m_vector[i];
+ if (!x) {
+ ArrayStorage *storage = m_storage;
+ ++storage->m_numValuesInVector;
+ if (i >= storage->m_length)
+ storage->m_length = i + 1;
+ }
+ x.set(globalData, this, v);
+ }
+
+ inline void initializeIndex(JSGlobalData& globalData, unsigned i, JSValue v)
+ {
+ ASSERT(canSetIndex(i));
+ ArrayStorage *storage = m_storage;
+#if CHECK_ARRAY_CONSISTENCY
+ ASSERT(storage->m_inCompactInitialization);
+#endif
+ // Check that we are initializing the next index in sequence.
+ ASSERT_UNUSED(i, i == storage->m_length);
+ // tryCreateUninitialized set m_numValuesInVector to the initialLength,
+ // check we do not try to initialize more than this number of properties.
+ ASSERT(storage->m_length < storage->m_numValuesInVector);
+ // It is improtant that we increment length here, so that all newly added
+ // values in the array still get marked during the initialization phase.
+ storage->m_vector[storage->m_length++].set(globalData, this, v);
+ }
+
+ inline void completeInitialization(unsigned newLength)
+ {
+ // Check that we have initialized as meny properties as we think we have.
+ ASSERT_UNUSED(newLength, newLength == m_storage->m_length);
+ // Check that the number of propreties initialized matches the initialLength.
+ ASSERT(m_storage->m_length == m_storage->m_numValuesInVector);
+#if CHECK_ARRAY_CONSISTENCY
+ ASSERT(m_storage->m_inCompactInitialization);
+ m_storage->m_inCompactInitialization = false;
+#endif
+ }
+
+ bool inSparseMode()
+ {
+ SparseArrayValueMap* map = m_storage->m_sparseValueMap;
+ return map && map->sparseMode();
+ }
+
+ void fillArgList(ExecState*, MarkedArgumentBuffer&);
+ void copyToArguments(ExecState*, CallFrame*, uint32_t length);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static ptrdiff_t storageOffset()
+ {
+ return OBJECT_OFFSETOF(JSArray, m_storage);
+ }
+
+ static ptrdiff_t vectorLengthOffset()
+ {
+ return OBJECT_OFFSETOF(JSArray, m_vectorLength);
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
+ static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
+ void* subclassData() const;
+ void setSubclassData(void*);
+
+ private:
+ bool getOwnPropertySlotSlowCase(ExecState*, unsigned propertyName, PropertySlot&);
+ void putByIndexBeyondVectorLength(JSGlobalData&, unsigned propertyName, JSValue);
+
+ unsigned getNewVectorLength(unsigned desiredLength);
+ bool increaseVectorLength(unsigned newLength);
+ bool unshiftCountSlowCase(unsigned count);
+
+ unsigned compactForSorting();
+
+ enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck };
+ void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck);
+
+ unsigned m_vectorLength; // The valid length of m_vector
+ unsigned m_indexBias; // The number of JSValue sized blocks before ArrayStorage.
+ ArrayStorage *m_storage;
+ };
+
+ JSArray* asArray(JSValue);
+
+ inline JSArray* asArray(JSCell* cell)
+ {
+ ASSERT(cell->inherits(&JSArray::s_info));
+ return static_cast<JSArray*>(cell);
+ }
+
+ inline JSArray* asArray(JSValue value)
+ {
+ return asArray(value.asCell());
+ }
+
+ inline bool isJSArray(JSCell* cell) { return cell->classInfo() == &JSArray::s_info; }
+ inline bool isJSArray(JSValue v) { return v.isCell() && isJSArray(v.asCell()); }
+
+ // Rule from ECMA 15.2 about what an array index is.
+ // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
+ inline unsigned Identifier::toArrayIndex(bool& ok) const
+ {
+ unsigned i = toUInt32(ok);
+ if (ok && i >= 0xFFFFFFFFU)
+ ok = false;
+ return i;
+ }
+
+} // namespace JSC
+
+#endif // JSArray_h
diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.cpp b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
new file mode 100644
index 000000000..549b6034f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSBoundFunction.h"
+
+#include "JSGlobalObject.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(JSBoundFunction);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSBoundFunction);
+
+const ClassInfo JSBoundFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSBoundFunction) };
+
+EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState* exec)
+{
+ JSBoundFunction* boundFunction = static_cast<JSBoundFunction*>(exec->callee());
+
+ ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true!
+ JSArray* boundArgs = asArray(boundFunction->boundArgs());
+
+ MarkedArgumentBuffer args;
+ for (unsigned i = 0; i < boundArgs->length(); ++i)
+ args.append(boundArgs->getIndex(i));
+ for (unsigned i = 0; i < exec->argumentCount(); ++i)
+ args.append(exec->argument(i));
+
+ JSObject* targetFunction = boundFunction->targetFunction();
+ CallData callData;
+ CallType callType = getCallData(targetFunction, callData);
+ ASSERT(callType != CallTypeNone);
+ return JSValue::encode(call(exec, targetFunction, callType, callData, boundFunction->boundThis(), args));
+}
+
+EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState* exec)
+{
+ JSBoundFunction* boundFunction = static_cast<JSBoundFunction*>(exec->callee());
+
+ ASSERT(isJSArray(boundFunction->boundArgs())); // Currently this is true!
+ JSArray* boundArgs = asArray(boundFunction->boundArgs());
+
+ MarkedArgumentBuffer args;
+ for (unsigned i = 0; i < boundArgs->length(); ++i)
+ args.append(boundArgs->getIndex(i));
+ for (unsigned i = 0; i < exec->argumentCount(); ++i)
+ args.append(exec->argument(i));
+
+ JSObject* targetFunction = boundFunction->targetFunction();
+ ConstructData constructData;
+ ConstructType constructType = getConstructData(targetFunction, constructData);
+ ASSERT(constructType != ConstructTypeNone);
+ return JSValue::encode(construct(exec, targetFunction, constructType, constructData, args));
+}
+
+JSBoundFunction* JSBoundFunction::create(ExecState* exec, JSGlobalObject* globalObject, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int length, const Identifier& name)
+{
+ ConstructData constructData;
+ ConstructType constructType = JSC::getConstructData(targetFunction, constructData);
+ bool canConstruct = constructType != ConstructTypeNone;
+
+ NativeExecutable* executable = exec->globalData().getHostFunction(boundFunctionCall, canConstruct ? boundFunctionConstruct : callHostFunctionAsConstructor);
+ JSBoundFunction* function = new (NotNull, allocateCell<JSBoundFunction>(*exec->heap())) JSBoundFunction(exec, globalObject, globalObject->boundFunctionStructure(), targetFunction, boundThis, boundArgs);
+
+ function->finishCreation(exec, executable, length, name);
+ return function;
+}
+
+bool JSBoundFunction::hasInstance(JSObject* object, ExecState* exec, JSValue value, JSValue)
+{
+ JSBoundFunction* thisObject = jsCast<JSBoundFunction*>(object);
+ // FIXME: our instanceof implementation will have already (incorrectly) performed
+ // a [[Get]] of .prototype from the bound function object, which is incorrect!
+ // https://bugs.webkit.org/show_bug.cgi?id=68656
+ JSValue proto = thisObject->m_targetFunction->get(exec, exec->propertyNames().prototype);
+ return thisObject->m_targetFunction->methodTable()->hasInstance(thisObject->m_targetFunction.get(), exec, value, proto);
+}
+
+JSBoundFunction::JSBoundFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs)
+ : Base(exec, globalObject, structure)
+ , m_targetFunction(exec->globalData(), this, targetFunction)
+ , m_boundThis(exec->globalData(), this, boundThis)
+ , m_boundArgs(exec->globalData(), this, boundArgs)
+{
+}
+
+void JSBoundFunction::finishCreation(ExecState* exec, NativeExecutable* executable, int length, const Identifier& name)
+{
+ Base::finishCreation(exec, executable, length, name);
+ ASSERT(inherits(&s_info));
+
+ initializeGetterSetterProperty(exec, exec->propertyNames().arguments, globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter);
+ initializeGetterSetterProperty(exec, exec->propertyNames().caller, globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter);
+}
+
+void JSBoundFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSBoundFunction* thisObject = jsCast<JSBoundFunction*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_targetFunction);
+ visitor.append(&thisObject->m_boundThis);
+ visitor.append(&thisObject->m_boundArgs);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSBoundFunction.h b/Source/JavaScriptCore/runtime/JSBoundFunction.h
new file mode 100644
index 000000000..c60d7db01
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSBoundFunction.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSBoundFunction_h
+#define JSBoundFunction_h
+
+#include "JSFunction.h"
+
+namespace JSC {
+
+EncodedJSValue JSC_HOST_CALL boundFunctionCall(ExecState*);
+EncodedJSValue JSC_HOST_CALL boundFunctionConstruct(ExecState*);
+
+class JSBoundFunction : public JSFunction {
+public:
+ typedef JSFunction Base;
+
+ static JSBoundFunction* create(ExecState*, JSGlobalObject*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs, int, const Identifier&);
+
+ static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue proto);
+
+ JSObject* targetFunction() { return m_targetFunction.get(); }
+ JSValue boundThis() { return m_boundThis.get(); }
+ JSValue boundArgs() { return m_boundArgs.get(); }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ ASSERT(globalObject);
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), &s_info);
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+protected:
+ const static unsigned StructureFlags = OverridesHasInstance | OverridesVisitChildren | Base::StructureFlags;
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+private:
+ JSBoundFunction(ExecState*, JSGlobalObject*, Structure*, JSObject* targetFunction, JSValue boundThis, JSValue boundArgs);
+
+ void finishCreation(ExecState*, NativeExecutable*, int, const Identifier&);
+
+ WriteBarrier<JSObject> m_targetFunction;
+ WriteBarrier<Unknown> m_boundThis;
+ WriteBarrier<Unknown> m_boundArgs;
+};
+
+} // namespace JSC
+
+#endif // JSFunction_h
diff --git a/Source/JavaScriptCore/runtime/JSByteArray.cpp b/Source/JavaScriptCore/runtime/JSByteArray.cpp
new file mode 100644
index 000000000..7478a08fb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSByteArray.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSByteArray.h"
+
+#include "JSGlobalObject.h"
+#include "PropertyNameArray.h"
+
+using namespace WTF;
+
+namespace JSC {
+
+const ClassInfo JSByteArray::s_info = { "ByteArray", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSByteArray) };
+
+JSByteArray::JSByteArray(ExecState* exec, Structure* structure, ByteArray* storage)
+ : JSNonFinalObject(exec->globalData(), structure)
+ , m_storage(storage)
+{
+}
+
+JSByteArray::~JSByteArray()
+{
+ ASSERT(jsCast<JSByteArray*>(this));
+}
+
+void JSByteArray::destroy(JSCell* cell)
+{
+ jsCast<JSByteArray*>(cell)->JSByteArray::~JSByteArray();
+}
+
+Structure* JSByteArray::createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const JSC::ClassInfo* classInfo)
+{
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), classInfo);
+}
+
+bool JSByteArray::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ JSByteArray* thisObject = jsCast<JSByteArray*>(cell);
+ bool ok;
+ unsigned index = propertyName.toUInt32(ok);
+ if (ok && thisObject->canAccessIndex(index)) {
+ slot.setValue(thisObject->getIndex(exec, index));
+ return true;
+ }
+ return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+}
+
+bool JSByteArray::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ JSByteArray* thisObject = jsCast<JSByteArray*>(object);
+ bool ok;
+ unsigned index = propertyName.toUInt32(ok);
+ if (ok && thisObject->canAccessIndex(index)) {
+ descriptor.setDescriptor(thisObject->getIndex(exec, index), DontDelete);
+ return true;
+ }
+ return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+}
+
+bool JSByteArray::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ JSByteArray* thisObject = jsCast<JSByteArray*>(cell);
+ if (thisObject->canAccessIndex(propertyName)) {
+ slot.setValue(thisObject->getIndex(exec, propertyName));
+ return true;
+ }
+ return JSObject::getOwnPropertySlot(thisObject, exec, Identifier::from(exec, propertyName), slot);
+}
+
+void JSByteArray::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSByteArray* thisObject = jsCast<JSByteArray*>(cell);
+ bool ok;
+ unsigned index = propertyName.toUInt32(ok);
+ if (ok) {
+ thisObject->setIndex(exec, index, value);
+ return;
+ }
+ JSObject::put(thisObject, exec, propertyName, value, slot);
+}
+
+void JSByteArray::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value)
+{
+ jsCast<JSByteArray*>(cell)->setIndex(exec, propertyName, value);
+}
+
+void JSByteArray::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSByteArray* thisObject = jsCast<JSByteArray*>(object);
+ unsigned length = thisObject->m_storage->length();
+ for (unsigned i = 0; i < length; ++i)
+ propertyNames.add(Identifier::from(exec, i));
+ JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+}
+
diff --git a/Source/JavaScriptCore/runtime/JSByteArray.h b/Source/JavaScriptCore/runtime/JSByteArray.h
new file mode 100644
index 000000000..754774d3e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSByteArray.h
@@ -0,0 +1,133 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSByteArray_h
+#define JSByteArray_h
+
+#include "JSObject.h"
+
+#include <wtf/ByteArray.h>
+
+namespace JSC {
+
+ class JSByteArray : public JSNonFinalObject {
+ friend class JSGlobalData;
+ public:
+ typedef JSNonFinalObject Base;
+
+ bool canAccessIndex(unsigned i) { return i < m_storage->length(); }
+ JSValue getIndex(ExecState*, unsigned i)
+ {
+ ASSERT(canAccessIndex(i));
+ return jsNumber(m_storage->data()[i]);
+ }
+
+ void setIndex(unsigned i, int value)
+ {
+ ASSERT(canAccessIndex(i));
+ if (value & ~0xFF) {
+ if (value < 0)
+ value = 0;
+ else
+ value = 255;
+ }
+ m_storage->data()[i] = static_cast<unsigned char>(value);
+ }
+
+ void setIndex(unsigned i, double value)
+ {
+ ASSERT(canAccessIndex(i));
+ if (!(value > 0)) // Clamp NaN to 0
+ value = 0;
+ else if (value > 255)
+ value = 255;
+ m_storage->data()[i] = static_cast<unsigned char>(value + 0.5);
+ }
+
+ void setIndex(ExecState* exec, unsigned i, JSValue value)
+ {
+ double byteValue = value.toNumber(exec);
+ if (exec->hadException())
+ return;
+ if (canAccessIndex(i))
+ setIndex(i, byteValue);
+ }
+
+ private:
+ JSByteArray(ExecState*, Structure*, ByteArray* storage);
+
+ public:
+ static JSByteArray* create(ExecState* exec, Structure* structure, ByteArray* storage)
+ {
+ JSByteArray* array = new (NotNull, allocateCell<JSByteArray>(*exec->heap())) JSByteArray(exec, structure, storage);
+ array->finishCreation(exec);
+ return array;
+ }
+
+ static Structure* createStructure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const JSC::ClassInfo* = &s_info);
+
+ static bool getOwnPropertySlot(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ static void put(JSC::JSCell*, JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&);
+ static void putByIndex(JSC::JSCell*, JSC::ExecState*, unsigned propertyName, JSC::JSValue);
+
+ static void getOwnPropertyNames(JSC::JSObject*, JSC::ExecState*, JSC::PropertyNameArray&, EnumerationMode);
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ size_t length() const { return m_storage->length(); }
+
+ WTF::ByteArray* storage() const { return m_storage.get(); }
+
+ ~JSByteArray();
+ static void destroy(JSCell*);
+
+ static size_t offsetOfStorage() { return OBJECT_OFFSETOF(JSByteArray, m_storage); }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
+
+ void finishCreation(ExecState* exec)
+ {
+ Base::finishCreation(exec->globalData());
+ putDirect(exec->globalData(), exec->globalData().propertyNames->length, jsNumber(m_storage->length()), ReadOnly | DontDelete);
+ }
+
+ private:
+ RefPtr<WTF::ByteArray> m_storage;
+ };
+
+ JSByteArray* asByteArray(JSValue value);
+ inline JSByteArray* asByteArray(JSValue value)
+ {
+ return static_cast<JSByteArray*>(value.asCell());
+ }
+
+ inline bool isJSByteArray(JSValue v) { return v.isCell() && v.asCell()->classInfo() == &JSByteArray::s_info; }
+
+} // namespace JSC
+
+#endif // JSByteArray_h
diff --git a/Source/JavaScriptCore/runtime/JSCell.cpp b/Source/JavaScriptCore/runtime/JSCell.cpp
new file mode 100644
index 000000000..065fd13ea
--- /dev/null
+++ b/Source/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 "NumberObject.h"
+#include <wtf/MathExtras.h>
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSCell);
+
+void JSCell::destroy(JSCell* cell)
+{
+ cell->JSCell::~JSCell();
+}
+
+bool JSCell::getString(ExecState* exec, UString&stringValue) const
+{
+ if (!isString())
+ return false;
+ stringValue = static_cast<const JSString*>(this)->value(exec);
+ return true;
+}
+
+UString JSCell::getString(ExecState* exec) const
+{
+ return isString() ? static_cast<const JSString*>(this)->value(exec) : UString();
+}
+
+JSObject* JSCell::getObject()
+{
+ return isObject() ? asObject(this) : 0;
+}
+
+const JSObject* JSCell::getObject() const
+{
+ return isObject() ? static_cast<const JSObject*>(this) : 0;
+}
+
+CallType JSCell::getCallData(JSCell*, CallData&)
+{
+ return CallTypeNone;
+}
+
+ConstructType JSCell::getConstructData(JSCell*, ConstructData&)
+{
+ return ConstructTypeNone;
+}
+
+bool JSCell::getOwnPropertySlot(JSCell* cell, 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 = cell->toObject(exec, exec->lexicalGlobalObject());
+ slot.setBase(object);
+ if (!object->getPropertySlot(exec, identifier, slot))
+ slot.setUndefined();
+ return true;
+}
+
+bool JSCell::getOwnPropertySlotByIndex(JSCell* cell, 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 = cell->toObject(exec, exec->lexicalGlobalObject());
+ slot.setBase(object);
+ if (!object->getPropertySlot(exec, identifier, slot))
+ slot.setUndefined();
+ return true;
+}
+
+void JSCell::put(JSCell* cell, ExecState* exec, const Identifier& identifier, JSValue value, PutPropertySlot& slot)
+{
+ JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
+ thisObject->methodTable()->put(thisObject, exec, identifier, value, slot);
+}
+
+void JSCell::putByIndex(JSCell* cell, ExecState* exec, unsigned identifier, JSValue value)
+{
+ JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
+ thisObject->methodTable()->putByIndex(thisObject, exec, identifier, value);
+}
+
+bool JSCell::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& identifier)
+{
+ JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
+ return thisObject->methodTable()->deleteProperty(thisObject, exec, identifier);
+}
+
+bool JSCell::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned identifier)
+{
+ JSObject* thisObject = cell->toObject(exec, exec->lexicalGlobalObject());
+ return thisObject->methodTable()->deletePropertyByIndex(thisObject, exec, identifier);
+}
+
+JSObject* JSCell::toThisObject(JSCell* cell, ExecState* exec)
+{
+ return cell->toObject(exec, exec->lexicalGlobalObject());
+}
+
+JSValue JSCell::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
+{
+ if (isString())
+ return static_cast<const JSString*>(this)->toPrimitive(exec, preferredType);
+ return static_cast<const JSObject*>(this)->toPrimitive(exec, preferredType);
+}
+
+bool JSCell::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value) const
+{
+ if (isString())
+ return static_cast<const JSString*>(this)->getPrimitiveNumber(exec, number, value);
+ return static_cast<const JSObject*>(this)->getPrimitiveNumber(exec, number, value);
+}
+
+double JSCell::toNumber(ExecState* exec) const
+{
+ if (isString())
+ return static_cast<const JSString*>(this)->toNumber(exec);
+ return static_cast<const JSObject*>(this)->toNumber(exec);
+}
+
+UString JSCell::toString(ExecState* exec) const
+{
+ if (isString())
+ return static_cast<const JSString*>(this)->toString(exec);
+ return static_cast<const JSObject*>(this)->toString(exec);
+}
+
+JSObject* JSCell::toObject(ExecState* exec, JSGlobalObject* globalObject) const
+{
+ if (isString())
+ return static_cast<const JSString*>(this)->toObject(exec, globalObject);
+ ASSERT(isObject());
+ return static_cast<JSObject*>(const_cast<JSCell*>(this));
+}
+
+void slowValidateCell(JSCell* cell)
+{
+ ASSERT_GC_OBJECT_LOOKS_VALID(cell);
+}
+
+void JSCell::defineGetter(JSObject*, ExecState*, const Identifier&, JSObject*, unsigned)
+{
+ ASSERT_NOT_REACHED();
+}
+
+void JSCell::defineSetter(JSObject*, ExecState*, const Identifier&, JSObject*, unsigned)
+{
+ ASSERT_NOT_REACHED();
+}
+
+JSValue JSCell::defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType)
+{
+ ASSERT_NOT_REACHED();
+ return jsUndefined();
+}
+
+void JSCell::getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ ASSERT_NOT_REACHED();
+}
+
+UString JSCell::className(const JSObject*)
+{
+ ASSERT_NOT_REACHED();
+ return UString();
+}
+
+void JSCell::getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode)
+{
+ ASSERT_NOT_REACHED();
+}
+
+bool JSCell::hasInstance(JSObject*, ExecState*, JSValue, JSValue)
+{
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+void JSCell::putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned)
+{
+ ASSERT_NOT_REACHED();
+}
+
+bool JSCell::defineOwnProperty(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&, bool)
+{
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+bool JSCell::getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&)
+{
+ ASSERT_NOT_REACHED();
+ return false;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSCell.h b/Source/JavaScriptCore/runtime/JSCell.h
new file mode 100644
index 000000000..47e336a86
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSCell.h
@@ -0,0 +1,344 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 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 "CallData.h"
+#include "CallFrame.h"
+#include "ConstructData.h"
+#include "Heap.h"
+#include "JSLock.h"
+#include "JSValueInlineMethods.h"
+#include "SlotVisitor.h"
+#include "WriteBarrier.h"
+#include <wtf/Noncopyable.h>
+
+namespace JSC {
+
+ class JSGlobalObject;
+ class Structure;
+ class PropertyDescriptor;
+ class PropertyNameArray;
+
+ enum EnumerationMode {
+ ExcludeDontEnumProperties,
+ IncludeDontEnumProperties
+ };
+
+ enum TypedArrayType {
+ TypedArrayNone,
+ TypedArrayInt8,
+ TypedArrayInt16,
+ TypedArrayInt32,
+ TypedArrayUint8,
+ TypedArrayUint16,
+ TypedArrayUint32,
+ TypedArrayFloat32,
+ TypedArrayFloat64
+ };
+
+ class JSCell {
+ friend class JSValue;
+ friend class MarkedBlock;
+
+ public:
+ enum CreatingEarlyCellTag { CreatingEarlyCell };
+ JSCell(CreatingEarlyCellTag);
+
+ protected:
+ JSCell(JSGlobalData&, Structure*);
+ static void destroy(JSCell*);
+
+ public:
+ // Querying the type.
+ bool isString() const;
+ bool isObject() const;
+ bool isGetterSetter() const;
+ bool inherits(const ClassInfo*) const;
+ bool isAPIValueWrapper() const;
+
+ Structure* structure() const;
+ void setStructure(JSGlobalData&, Structure*);
+ void clearStructure() { m_structure.clear(); }
+
+ // Extracting the value.
+ bool getString(ExecState* exec, UString&) const;
+ UString getString(ExecState* exec) const; // null string if not a string
+ JSObject* getObject(); // NULL if not an object
+ const JSObject* getObject() const; // NULL if not an object
+
+ static CallType getCallData(JSCell*, CallData&);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+
+ // Basic conversions.
+ JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
+ bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
+ bool toBoolean(ExecState*) const;
+ double toNumber(ExecState*) const;
+ UString toString(ExecState*) const;
+ JSObject* toObject(ExecState*, JSGlobalObject*) const;
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ // Object operations, with the toObject operation included.
+ const ClassInfo* classInfo() const;
+ const ClassInfo* validatedClassInfo() const;
+ const MethodTable* methodTable() const;
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+ static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue);
+
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
+ static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
+
+ static JSObject* toThisObject(JSCell*, ExecState*);
+
+ void zap() { *reinterpret_cast<uintptr_t**>(this) = 0; }
+ bool isZapped() const { return !*reinterpret_cast<uintptr_t* const*>(this); }
+
+ // FIXME: Rename getOwnPropertySlot to virtualGetOwnPropertySlot, and
+ // fastGetOwnPropertySlot to getOwnPropertySlot. Callers should always
+ // call this function, not its slower virtual counterpart. (For integer
+ // property names, we want a similar interface with appropriate optimizations.)
+ bool fastGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
+ JSValue fastGetOwnProperty(ExecState*, const UString&);
+
+ static ptrdiff_t structureOffset()
+ {
+ return OBJECT_OFFSETOF(JSCell, m_structure);
+ }
+
+ static ptrdiff_t classInfoOffset()
+ {
+ return OBJECT_OFFSETOF(JSCell, m_classInfo);
+ }
+
+ void* structureAddress()
+ {
+ return &m_structure;
+ }
+
+#if ENABLE(GC_VALIDATION)
+ Structure* unvalidatedStructure() { return m_structure.unvalidatedGet(); }
+#endif
+
+ static const TypedArrayType TypedArrayStorageType = TypedArrayNone;
+ protected:
+
+ void finishCreation(JSGlobalData&);
+ void finishCreation(JSGlobalData&, Structure*, CreatingEarlyCellTag);
+
+ // Base implementation; for non-object classes implements getPropertySlot.
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+
+ // Dummy implementations of override-able static functions for classes to put in their MethodTable
+ static NO_RETURN_DUE_TO_ASSERT void defineGetter(JSObject*, ExecState*, const Identifier&, JSObject*, unsigned);
+ static NO_RETURN_DUE_TO_ASSERT void defineSetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0);
+ static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
+ static NO_RETURN_DUE_TO_ASSERT void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static NO_RETURN_DUE_TO_ASSERT void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static UString className(const JSObject*);
+ static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty);
+ static NO_RETURN_DUE_TO_ASSERT void putWithAttributes(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes);
+ static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ private:
+ const ClassInfo* m_classInfo;
+ WriteBarrier<Structure> m_structure;
+ };
+
+ inline JSCell::JSCell(CreatingEarlyCellTag)
+ {
+ }
+
+ inline void JSCell::finishCreation(JSGlobalData& globalData)
+ {
+#if ENABLE(GC_VALIDATION)
+ ASSERT(globalData.isInitializingObject());
+ globalData.setInitializingObject(false);
+#else
+ UNUSED_PARAM(globalData);
+#endif
+ ASSERT(m_structure);
+ }
+
+ inline Structure* JSCell::structure() const
+ {
+ return m_structure.get();
+ }
+
+ inline const ClassInfo* JSCell::classInfo() const
+ {
+ return m_classInfo;
+ }
+
+ inline void JSCell::visitChildren(JSCell* cell, SlotVisitor& visitor)
+ {
+ visitor.append(&cell->m_structure);
+ }
+
+ // --- JSValue inlines ----------------------------
+
+ inline bool JSValue::isString() const
+ {
+ return isCell() && asCell()->isString();
+ }
+
+ inline bool JSValue::isPrimitive() const
+ {
+ return !isCell() || asCell()->isString();
+ }
+
+ inline bool JSValue::isGetterSetter() const
+ {
+ return isCell() && asCell()->isGetterSetter();
+ }
+
+ inline bool JSValue::isObject() const
+ {
+ return isCell() && asCell()->isObject();
+ }
+
+ inline bool JSValue::getString(ExecState* exec, UString& s) const
+ {
+ return isCell() && asCell()->getString(exec, s);
+ }
+
+ inline UString JSValue::getString(ExecState* exec) const
+ {
+ return isCell() ? asCell()->getString(exec) : UString();
+ }
+
+ template <typename Base> UString HandleConverter<Base, Unknown>::getString(ExecState* exec) const
+ {
+ return jsValue().getString(exec);
+ }
+
+ inline JSObject* JSValue::getObject() const
+ {
+ return isCell() ? asCell()->getObject() : 0;
+ }
+
+ ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
+ {
+ if (isInt32()) {
+ int32_t i = asInt32();
+ v = static_cast<uint32_t>(i);
+ return i >= 0;
+ }
+ if (isDouble()) {
+ double d = asDouble();
+ v = static_cast<uint32_t>(d);
+ return v == d;
+ }
+ return false;
+ }
+
+ inline JSValue JSValue::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
+ {
+ return isCell() ? asCell()->toPrimitive(exec, preferredType) : asValue();
+ }
+
+ inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue& value)
+ {
+ if (isInt32()) {
+ number = asInt32();
+ value = *this;
+ return true;
+ }
+ if (isDouble()) {
+ number = asDouble();
+ value = *this;
+ return true;
+ }
+ if (isCell())
+ return asCell()->getPrimitiveNumber(exec, number, value);
+ if (isTrue()) {
+ number = 1.0;
+ value = *this;
+ return true;
+ }
+ if (isFalse() || isNull()) {
+ number = 0.0;
+ value = *this;
+ return true;
+ }
+ ASSERT(isUndefined());
+ number = std::numeric_limits<double>::quiet_NaN();
+ value = *this;
+ return true;
+ }
+
+ ALWAYS_INLINE double JSValue::toNumber(ExecState* exec) const
+ {
+ if (isInt32())
+ return asInt32();
+ if (isDouble())
+ return asDouble();
+ return toNumberSlowCase(exec);
+ }
+
+ inline JSObject* JSValue::toObject(ExecState* exec) const
+ {
+ return isCell() ? asCell()->toObject(exec, exec->lexicalGlobalObject()) : toObjectSlowCase(exec, exec->lexicalGlobalObject());
+ }
+
+ inline JSObject* JSValue::toObject(ExecState* exec, JSGlobalObject* globalObject) const
+ {
+ return isCell() ? asCell()->toObject(exec, globalObject) : toObjectSlowCase(exec, globalObject);
+ }
+
+ template <typename T> void* allocateCell(Heap& heap)
+ {
+#if ENABLE(GC_VALIDATION)
+ ASSERT(sizeof(T) == T::s_info.cellSize);
+ ASSERT(!heap.globalData()->isInitializingObject());
+ heap.globalData()->setInitializingObject(true);
+#endif
+ JSCell* result = static_cast<JSCell*>(heap.allocate(sizeof(T)));
+ result->clearStructure();
+ return result;
+ }
+
+ inline bool isZapped(const JSCell* cell)
+ {
+ return cell->isZapped();
+ }
+
+ template<typename To, typename From>
+ inline To jsCast(From* from)
+ {
+ ASSERT(from->inherits(&WTF::RemovePointer<To>::Type::s_info));
+ return static_cast<To>(from);
+ }
+
+ template<typename To, typename From>
+ inline To jsDynamicCast(From* from)
+ {
+ return from->inherits(&WTF::RemovePointer<To>::Type::s_info) ? static_cast<To>(from) : 0;
+ }
+
+} // namespace JSC
+
+#endif // JSCell_h
diff --git a/Source/JavaScriptCore/runtime/JSChunk.cpp b/Source/JavaScriptCore/runtime/JSChunk.cpp
new file mode 100644
index 000000000..f064de8bb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSChunk.cpp
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSChunk.h"
+
diff --git a/Source/JavaScriptCore/runtime/JSChunk.h b/Source/JavaScriptCore/runtime/JSChunk.h
new file mode 100644
index 000000000..bae2bc75f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSChunk.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSChunk_h
+#define JSChunk_h
+
+
+
+#endif // JSChunk_h
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.cpp b/Source/JavaScriptCore/runtime/JSDateMath.cpp
new file mode 100644
index 000000000..863073338
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSDateMath.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2007-2009 Torch Mobile, Inc.
+ * Copyright (C) 2010 &yet, LLC. (nate@andyet.net)
+ *
+ * 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.
+
+ * Copyright 2006-2008 the V8 project authors. All rights reserved.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * * Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials provided
+ * with the distribution.
+ * * Neither the name of Google Inc. 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 THE COPYRIGHT HOLDERS AND 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 THE COPYRIGHT
+ * OWNER 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 "JSDateMath.h"
+
+#include "Assertions.h"
+#include "ASCIICType.h"
+#include "CurrentTime.h"
+#include "JSObject.h"
+#include "MathExtras.h"
+#include "ScopeChain.h"
+#include "StdLibExtras.h"
+#include "StringExtras.h"
+
+#include <algorithm>
+#include <limits.h>
+#include <limits>
+#include <stdint.h>
+#include <time.h>
+#include <wtf/text/StringBuilder.h>
+
+#if HAVE(ERRNO_H)
+#include <errno.h>
+#endif
+
+#if OS(WINCE)
+extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t);
+extern "C" struct tm * localtime(const time_t *timer);
+#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 {
+
+static inline double timeToMS(double hour, double min, double sec, double ms)
+{
+ return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms);
+}
+
+static inline int msToSeconds(double ms)
+{
+ double result = fmod(floor(ms / msPerSecond), secondsPerMinute);
+ if (result < 0)
+ result += secondsPerMinute;
+ return static_cast<int>(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;
+}
+
+// Get the DST offset for the time passed in.
+//
+// NOTE: The implementation relies on the fact that no time zones have
+// more than one daylight savings offset change per month.
+// If this function is called with NaN it returns NaN.
+static double getDSTOffset(ExecState* exec, double ms, double utcOffset)
+{
+ DSTOffsetCache& cache = exec->globalData().dstOffsetCache;
+ double start = cache.start;
+ double end = cache.end;
+
+ if (start <= ms) {
+ // If the time fits in the cached interval, return the cached offset.
+ if (ms <= end) return cache.offset;
+
+ // Compute a possible new interval end.
+ double newEnd = end + cache.increment;
+
+ if (ms <= newEnd) {
+ double endOffset = calculateDSTOffset(newEnd, utcOffset);
+ if (cache.offset == endOffset) {
+ // If the offset at the end of the new interval still matches
+ // the offset in the cache, we grow the cached time interval
+ // and return the offset.
+ cache.end = newEnd;
+ cache.increment = msPerMonth;
+ return endOffset;
+ } else {
+ double offset = calculateDSTOffset(ms, utcOffset);
+ if (offset == endOffset) {
+ // The offset at the given time is equal to the offset at the
+ // new end of the interval, so that means that we've just skipped
+ // the point in time where the DST offset change occurred. Updated
+ // the interval to reflect this and reset the increment.
+ cache.start = ms;
+ cache.end = newEnd;
+ cache.increment = msPerMonth;
+ } else {
+ // The interval contains a DST offset change and the given time is
+ // before it. Adjust the increment to avoid a linear search for
+ // the offset change point and change the end of the interval.
+ cache.increment /= 3;
+ cache.end = ms;
+ }
+ // Update the offset in the cache and return it.
+ cache.offset = offset;
+ return offset;
+ }
+ }
+ }
+
+ // Compute the DST offset for the time and shrink the cache interval
+ // to only contain the time. This allows fast repeated DST offset
+ // computations for the same time.
+ double offset = calculateDSTOffset(ms, utcOffset);
+ cache.offset = offset;
+ cache.start = ms;
+ cache.end = ms;
+ cache.increment = msPerMonth;
+ return offset;
+}
+
+/*
+ * Get the difference in milliseconds between this time zone and UTC (GMT)
+ * NOT including DST.
+ */
+double getUTCOffset(ExecState* exec)
+{
+ double utcOffset = exec->globalData().cachedUTCOffset;
+ if (!isnan(utcOffset))
+ return utcOffset;
+ exec->globalData().cachedUTCOffset = calculateUTCOffset();
+ return exec->globalData().cachedUTCOffset;
+}
+
+double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC)
+{
+ double day = dateToDaysFrom1970(t.year + 1900, t.month, t.monthDay);
+ double ms = timeToMS(t.hour, t.minute, t.second, milliSeconds);
+ double result = (day * WTF::msPerDay) + ms;
+
+ if (!inputIsUTC) { // convert to UTC
+ double utcOffset = getUTCOffset(exec);
+ result -= utcOffset;
+ result -= getDSTOffset(exec, result, utcOffset);
+ }
+
+ return result;
+}
+
+// input is UTC
+void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm)
+{
+ double dstOff = 0.0;
+ double utcOff = 0.0;
+ if (!outputIsUTC) {
+ utcOff = getUTCOffset(exec);
+ dstOff = getDSTOffset(exec, 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) / WTF::msPerSecond);
+ tm.timeZone = nullptr;
+}
+
+double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateString)
+{
+ ASSERT(exec);
+ bool haveTZ;
+ int offset;
+ double ms = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset);
+ if (isnan(ms))
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // fall back to local timezone
+ if (!haveTZ) {
+ double utcOffset = getUTCOffset(exec);
+ double dstOffset = getDSTOffset(exec, ms, utcOffset);
+ offset = static_cast<int>((utcOffset + dstOffset) / WTF::msPerMinute);
+ }
+ return ms - (offset * WTF::msPerMinute);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSDateMath.h b/Source/JavaScriptCore/runtime/JSDateMath.h
new file mode 100644
index 000000000..ba6d647dd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSDateMath.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ * Copyright (C) 2010 Research In Motion Limited. 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 JSDateMath_h
+#define JSDateMath_h
+
+#include <wtf/DateMath.h>
+
+namespace JSC {
+
+class ExecState;
+struct GregorianDateTime;
+
+void msToGregorianDateTime(ExecState*, double, bool outputIsUTC, GregorianDateTime&);
+double gregorianDateTimeToMS(ExecState*, const GregorianDateTime&, double, bool inputIsUTC);
+double getUTCOffset(ExecState*);
+double parseDateFromNullTerminatedCharacters(ExecState*, const char* dateString);
+
+// Intentionally overridding the default tm of the system.
+// The members of tm differ on various operating systems.
+struct GregorianDateTime {
+ WTF_MAKE_NONCOPYABLE(GregorianDateTime);
+public:
+ GregorianDateTime()
+ : second(0)
+ , minute(0)
+ , hour(0)
+ , weekDay(0)
+ , monthDay(0)
+ , yearDay(0)
+ , month(0)
+ , year(0)
+ , isDST(0)
+ , utcOffset(0)
+ {
+ }
+
+ GregorianDateTime(ExecState* exec, 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)
+ {
+ UNUSED_PARAM(exec);
+#if HAVE(TM_GMTOFF)
+ utcOffset = static_cast<int>(inTm.tm_gmtoff);
+#else
+ utcOffset = static_cast<int>(getUTCOffset(exec) / WTF::msPerSecond + (isDST ? WTF::secondsPerHour : 0));
+#endif
+
+#if HAVE(TM_ZONE)
+ int inZoneSize = strlen(inTm.tm_zone) + 1;
+ timeZone = adoptArrayPtr(new char[inZoneSize]);
+ strncpy(timeZone.get(), inTm.tm_zone, inZoneSize);
+#else
+ timeZone = nullptr;
+#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 HAVE(TM_GMTOFF)
+ ret.tm_gmtoff = static_cast<long>(utcOffset);
+#endif
+#if HAVE(TM_ZONE)
+ ret.tm_zone = timeZone.get();
+#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.get()) + 1;
+ timeZone = adoptArrayPtr(new char[inZoneSize]);
+ strncpy(timeZone.get(), rhs.timeZone.get(), inZoneSize);
+ } else
+ timeZone = nullptr;
+ }
+
+ int second;
+ int minute;
+ int hour;
+ int weekDay;
+ int monthDay;
+ int yearDay;
+ int month;
+ int year;
+ int isDST;
+ int utcOffset;
+ OwnArrayPtr<char> timeZone;
+};
+
+static inline int gmtoffset(const GregorianDateTime& t)
+{
+ return t.utcOffset;
+}
+
+} // namespace JSC
+
+#endif // JSDateMath_h
diff --git a/Source/JavaScriptCore/runtime/JSExportMacros.h b/Source/JavaScriptCore/runtime/JSExportMacros.h
new file mode 100644
index 000000000..884805f86
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSExportMacros.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE 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.
+ *
+ * This file handles shared library symbol export decorations. It is recommended
+ * that all WebKit projects use these definitions so that symbol exports work
+ * properly on all platforms and compilers that WebKit builds under.
+ */
+
+#ifndef JSExportMacros_h
+#define JSExportMacros_h
+
+#include <wtf/Platform.h>
+#include <wtf/ExportMacros.h>
+
+// See note in wtf/Platform.h for more info on EXPORT_MACROS.
+#if USE(EXPORT_MACROS)
+
+#if defined(BUILDING_JavaScriptCore)
+#define JS_EXPORT_PRIVATE WTF_EXPORT
+#else
+#define JS_EXPORT_PRIVATE WTF_IMPORT
+#endif
+
+#define JS_EXPORT_HIDDEN WTF_HIDDEN
+#define JS_EXPORTDATA JS_EXPORT_PRIVATE
+#define JS_EXPORTCLASS JS_EXPORT_PRIVATE
+
+#else // !USE(EXPORT_MACROS)
+
+#if !PLATFORM(CHROMIUM) && OS(WINDOWS) && !defined(BUILDING_WX__) && !COMPILER(GCC)
+
+#if defined(BUILDING_JavaScriptCore)
+#define JS_EXPORTDATA __declspec(dllexport)
+#else
+#define JS_EXPORTDATA __declspec(dllimport)
+#endif
+
+#define JS_EXPORTCLASS JS_EXPORTDATA
+
+#else // !PLATFORM...
+
+#define JS_EXPORTDATA
+#define JS_EXPORTCLASS
+
+#endif // !PLATFORM...
+
+#define JS_EXPORT_PRIVATE
+#define JS_EXPORT_HIDDEN
+
+#endif // USE(EXPORT_MACROS)
+
+#endif // JSExportMacros_h
diff --git a/Source/JavaScriptCore/runtime/JSFunction.cpp b/Source/JavaScriptCore/runtime/JSFunction.cpp
new file mode 100644
index 000000000..65470a53f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSFunction.cpp
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2007 Maks Orlovich
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "JSFunction.h"
+
+#include "CodeBlock.h"
+#include "CommonIdentifiers.h"
+#include "CallFrame.h"
+#include "ExceptionHelpers.h"
+#include "FunctionPrototype.h"
+#include "JSArray.h"
+#include "JSGlobalObject.h"
+#include "JSNotAnObject.h"
+#include "Interpreter.h"
+#include "ObjectPrototype.h"
+#include "Parser.h"
+#include "PropertyNameArray.h"
+#include "ScopeChainMark.h"
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace JSC {
+EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState* exec)
+{
+ return throwVMError(exec, createNotAConstructorError(exec, exec->callee()));
+}
+
+ASSERT_CLASS_FITS_IN_CELL(JSFunction);
+
+const ClassInfo JSFunction::s_info = { "Function", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFunction) };
+
+bool JSFunction::isHostFunctionNonInline() const
+{
+ return isHostFunction();
+}
+
+JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const Identifier& name, NativeFunction nativeFunction, NativeFunction nativeConstructor)
+{
+ NativeExecutable* executable = exec->globalData().getHostFunction(nativeFunction, nativeConstructor);
+ JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, globalObject, globalObject->functionStructure());
+ // Can't do this during initialization because getHostFunction might do a GC allocation.
+ function->finishCreation(exec, executable, length, name);
+ return function;
+}
+
+JSFunction* JSFunction::create(ExecState* exec, JSGlobalObject* globalObject, int length, const Identifier& name, NativeExecutable* nativeExecutable)
+{
+ JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, globalObject, globalObject->functionStructure());
+ function->finishCreation(exec, nativeExecutable, length, name);
+ return function;
+}
+
+JSFunction::JSFunction(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ : Base(exec->globalData(), structure)
+ , m_executable()
+ , m_scopeChain(exec->globalData(), this, globalObject->globalScopeChain())
+{
+}
+
+JSFunction::JSFunction(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChainNode)
+ : Base(exec->globalData(), scopeChainNode->globalObject->functionStructure())
+ , m_executable(exec->globalData(), this, executable)
+ , m_scopeChain(exec->globalData(), this, scopeChainNode)
+{
+}
+
+void JSFunction::finishCreation(ExecState* exec, NativeExecutable* executable, int length, const Identifier& name)
+{
+ Base::finishCreation(exec->globalData());
+ ASSERT(inherits(&s_info));
+ m_executable.set(exec->globalData(), this, executable);
+ putDirect(exec->globalData(), exec->globalData().propertyNames->name, jsString(exec, name.isNull() ? "" : name.ustring()), DontDelete | ReadOnly | DontEnum);
+ putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(length), DontDelete | ReadOnly | DontEnum);
+}
+
+void JSFunction::finishCreation(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChainNode)
+{
+ Base::finishCreation(exec->globalData());
+ ASSERT(inherits(&s_info));
+
+ // Switching the structure here is only safe if we currently have the function structure!
+ ASSERT(structure() == scopeChainNode->globalObject->functionStructure());
+ setStructure(exec->globalData(), scopeChainNode->globalObject->namedFunctionStructure());
+ putDirectOffset(exec->globalData(), scopeChainNode->globalObject->functionNameOffset(), executable->nameValue());
+}
+
+void JSFunction::destroy(JSCell* cell)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(cell);
+ ASSERT(thisObject->classInfo()->isSubClassOf(&JSFunction::s_info));
+ thisObject->JSFunction::~JSFunction();
+}
+
+const UString& JSFunction::name(ExecState* exec)
+{
+ return asString(getDirect(exec->globalData(), exec->globalData().propertyNames->name))->tryGetValue();
+}
+
+const UString JSFunction::displayName(ExecState* exec)
+{
+ JSValue displayName = getDirect(exec->globalData(), exec->globalData().propertyNames->displayName);
+
+ if (displayName && isJSString(displayName))
+ return asString(displayName)->tryGetValue();
+
+ return UString();
+}
+
+const UString JSFunction::calculatedDisplayName(ExecState* exec)
+{
+ const UString explicitName = displayName(exec);
+
+ if (!explicitName.isEmpty())
+ return explicitName;
+
+ return name(exec);
+}
+
+const SourceCode* JSFunction::sourceCode() const
+{
+ if (isHostFunction())
+ return 0;
+ return &jsExecutable()->source();
+}
+
+void JSFunction::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ Base::visitChildren(thisObject, visitor);
+
+ visitor.append(&thisObject->m_scopeChain);
+ if (thisObject->m_executable)
+ visitor.append(&thisObject->m_executable);
+}
+
+CallType JSFunction::getCallData(JSCell* cell, CallData& callData)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(cell);
+ if (thisObject->isHostFunction()) {
+ callData.native.function = thisObject->nativeFunction();
+ return CallTypeHost;
+ }
+ callData.js.functionExecutable = thisObject->jsExecutable();
+ callData.js.scopeChain = thisObject->scope();
+ return CallTypeJS;
+}
+
+JSValue JSFunction::argumentsGetter(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ JSFunction* thisObj = asFunction(slotBase);
+ ASSERT(!thisObj->isHostFunction());
+ return exec->interpreter()->retrieveArguments(exec, thisObj);
+}
+
+JSValue JSFunction::callerGetter(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ JSFunction* thisObj = asFunction(slotBase);
+ ASSERT(!thisObj->isHostFunction());
+ return exec->interpreter()->retrieveCaller(exec, thisObj);
+}
+
+JSValue JSFunction::lengthGetter(ExecState*, JSValue slotBase, const Identifier&)
+{
+ JSFunction* thisObj = asFunction(slotBase);
+ ASSERT(!thisObj->isHostFunction());
+ return jsNumber(thisObj->jsExecutable()->parameterCount());
+}
+
+bool JSFunction::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(cell);
+ if (thisObject->isHostFunction())
+ return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+
+ if (propertyName == exec->propertyNames().prototype) {
+ WriteBarrierBase<Unknown>* location = thisObject->getDirectLocation(exec->globalData(), propertyName);
+
+ if (!location) {
+ JSObject* prototype = constructEmptyObject(exec, thisObject->globalObject()->emptyObjectStructure());
+ prototype->putDirect(exec->globalData(), exec->propertyNames().constructor, thisObject, DontEnum);
+ PutPropertySlot slot;
+ thisObject->putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | DontEnum, false, slot);
+ location = thisObject->getDirectLocation(exec->globalData(), exec->propertyNames().prototype);
+ }
+
+ slot.setValue(thisObject, location->get(), thisObject->offsetForLocation(location));
+ }
+
+ if (propertyName == exec->propertyNames().arguments) {
+ if (thisObject->jsExecutable()->isStrictMode()) {
+ bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ if (!result) {
+ thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter);
+ result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ ASSERT(result);
+ }
+ return result;
+ }
+ slot.setCacheableCustom(thisObject, argumentsGetter);
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().length) {
+ slot.setCacheableCustom(thisObject, lengthGetter);
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().caller) {
+ if (thisObject->jsExecutable()->isStrictMode()) {
+ bool result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ if (!result) {
+ thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter);
+ result = Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ ASSERT(result);
+ }
+ return result;
+ }
+ slot.setCacheableCustom(thisObject, callerGetter);
+ return true;
+ }
+
+ return Base::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+}
+
+bool JSFunction::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(object);
+ if (thisObject->isHostFunction())
+ return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+
+ if (propertyName == exec->propertyNames().prototype) {
+ PropertySlot slot;
+ thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+ }
+
+ if (propertyName == exec->propertyNames().arguments) {
+ if (thisObject->jsExecutable()->isStrictMode()) {
+ bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+ if (!result) {
+ thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter);
+ result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+ ASSERT(result);
+ }
+ return result;
+ }
+ descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, thisObject), ReadOnly | DontEnum | DontDelete);
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().length) {
+ descriptor.setDescriptor(jsNumber(thisObject->jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete);
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().caller) {
+ if (thisObject->jsExecutable()->isStrictMode()) {
+ bool result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+ if (!result) {
+ thisObject->initializeGetterSetterProperty(exec, propertyName, thisObject->globalObject()->throwTypeErrorGetterSetter(exec), DontDelete | DontEnum | Getter | Setter);
+ result = Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+ ASSERT(result);
+ }
+ return result;
+ }
+ descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, thisObject), ReadOnly | DontEnum | DontDelete);
+ return true;
+ }
+
+ return Base::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+}
+
+void JSFunction::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(object);
+ if (!thisObject->isHostFunction() && (mode == IncludeDontEnumProperties)) {
+ // Make sure prototype has been reified.
+ PropertySlot slot;
+ thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, exec->propertyNames().prototype, slot);
+
+ propertyNames.add(exec->propertyNames().arguments);
+ propertyNames.add(exec->propertyNames().caller);
+ propertyNames.add(exec->propertyNames().length);
+ }
+ Base::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+void JSFunction::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(cell);
+ if (thisObject->isHostFunction()) {
+ Base::put(thisObject, exec, propertyName, value, slot);
+ return;
+ }
+ if (propertyName == exec->propertyNames().prototype) {
+ // Make sure prototype has been reified, such that it can only be overwritten
+ // following the rules set out in ECMA-262 8.12.9.
+ PropertySlot slot;
+ thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ }
+ if (thisObject->jsExecutable()->isStrictMode() && (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().caller)) {
+ // This will trigger the property to be reified, if this is not already the case!
+ bool okay = thisObject->hasProperty(exec, propertyName);
+ ASSERT_UNUSED(okay, okay);
+ Base::put(thisObject, exec, propertyName, value, slot);
+ return;
+ }
+ if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
+ return;
+ Base::put(thisObject, exec, propertyName, value, slot);
+}
+
+bool JSFunction::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(cell);
+ if (thisObject->isHostFunction())
+ return Base::deleteProperty(thisObject, exec, propertyName);
+ if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
+ return false;
+ return Base::deleteProperty(thisObject, exec, propertyName);
+}
+
+// ECMA 13.2.2 [[Construct]]
+ConstructType JSFunction::getConstructData(JSCell* cell, ConstructData& constructData)
+{
+ JSFunction* thisObject = jsCast<JSFunction*>(cell);
+ if (thisObject->isHostFunction()) {
+ constructData.native.function = thisObject->nativeConstructor();
+ return ConstructTypeHost;
+ }
+ constructData.js.functionExecutable = thisObject->jsExecutable();
+ constructData.js.scopeChain = thisObject->scope();
+ return ConstructTypeJS;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSFunction.h b/Source/JavaScriptCore/runtime/JSFunction.h
new file mode 100644
index 000000000..5118f8b10
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSFunction.h
@@ -0,0 +1,163 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2007 Maks Orlovich
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef JSFunction_h
+#define JSFunction_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+ class ExecutableBase;
+ class FunctionExecutable;
+ class FunctionPrototype;
+ class JSActivation;
+ class JSGlobalObject;
+ class NativeExecutable;
+ class SourceCode;
+ namespace DFG {
+ class SpeculativeJIT;
+ class JITCompiler;
+ }
+
+ EncodedJSValue JSC_HOST_CALL callHostFunctionAsConstructor(ExecState*);
+
+ class JSFunction : public JSNonFinalObject {
+ friend class JIT;
+ friend class DFG::SpeculativeJIT;
+ friend class DFG::JITCompiler;
+ friend class JSGlobalData;
+
+ public:
+ typedef JSNonFinalObject Base;
+
+ static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeFunction nativeFunction, NativeFunction nativeConstructor = callHostFunctionAsConstructor);
+ static JSFunction* create(ExecState*, JSGlobalObject*, int length, const Identifier& name, NativeExecutable* nativeExecutable);
+
+ static JSFunction* create(ExecState* exec, FunctionExecutable* executable, ScopeChainNode* scopeChain)
+ {
+ JSFunction* function = new (NotNull, allocateCell<JSFunction>(*exec->heap())) JSFunction(exec, executable, scopeChain);
+ ASSERT(function->structure()->globalObject());
+ function->finishCreation(exec, executable, scopeChain);
+ return function;
+ }
+
+ static void destroy(JSCell*);
+
+ const UString& name(ExecState*);
+ const UString displayName(ExecState*);
+ const UString calculatedDisplayName(ExecState*);
+
+ ScopeChainNode* scope()
+ {
+ ASSERT(!isHostFunctionNonInline());
+ return m_scopeChain.get();
+ }
+ // This method may be called for host functins, in which case it
+ // will return an arbitrary value. This should only be used for
+ // optimized paths in which the return value does not matter for
+ // host functions, and checking whether the function is a host
+ // function is deemed too expensive.
+ ScopeChainNode* scopeUnchecked()
+ {
+ return m_scopeChain.get();
+ }
+ void setScope(JSGlobalData& globalData, ScopeChainNode* scopeChain)
+ {
+ ASSERT(!isHostFunctionNonInline());
+ m_scopeChain.set(globalData, this, scopeChain);
+ }
+
+ ExecutableBase* executable() const { return m_executable.get(); }
+
+ // To call either of these methods include Executable.h
+ inline bool isHostFunction() const;
+ FunctionExecutable* jsExecutable() const;
+
+ const SourceCode* sourceCode() const;
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ ASSERT(globalObject);
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(JSFunctionType, StructureFlags), &s_info);
+ }
+
+ NativeFunction nativeFunction();
+ NativeFunction nativeConstructor();
+
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+
+ static inline size_t offsetOfScopeChain()
+ {
+ return OBJECT_OFFSETOF(JSFunction, m_scopeChain);
+ }
+
+ static inline size_t offsetOfExecutable()
+ {
+ return OBJECT_OFFSETOF(JSFunction, m_executable);
+ }
+
+ protected:
+ const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesVisitChildren | OverridesGetPropertyNames | JSObject::StructureFlags;
+
+ JSFunction(ExecState*, JSGlobalObject*, Structure*);
+ JSFunction(ExecState*, FunctionExecutable*, ScopeChainNode*);
+
+ void finishCreation(ExecState*, NativeExecutable*, int length, const Identifier& name);
+ void finishCreation(ExecState*, FunctionExecutable*, ScopeChainNode*);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode = ExcludeDontEnumProperties);
+
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ private:
+ bool isHostFunctionNonInline() const;
+
+ static JSValue argumentsGetter(ExecState*, JSValue, const Identifier&);
+ static JSValue callerGetter(ExecState*, JSValue, const Identifier&);
+ static JSValue lengthGetter(ExecState*, JSValue, const Identifier&);
+
+ WriteBarrier<ExecutableBase> m_executable;
+ WriteBarrier<ScopeChainNode> m_scopeChain;
+ };
+
+ JSFunction* asFunction(JSValue);
+
+ inline JSFunction* asFunction(JSValue value)
+ {
+ ASSERT(asObject(value)->inherits(&JSFunction::s_info));
+ return static_cast<JSFunction*>(asObject(value));
+ }
+
+} // namespace JSC
+
+#endif // JSFunction_h
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.cpp b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
new file mode 100644
index 000000000..dab3f24ba
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.cpp
@@ -0,0 +1,528 @@
+/*
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 "Heap.h"
+#include "CommonIdentifiers.h"
+#include "DebuggerActivation.h"
+#include "FunctionConstructor.h"
+#include "GetterSetter.h"
+#include "Interpreter.h"
+#include "JSActivation.h"
+#include "JSAPIValueWrapper.h"
+#include "JSArray.h"
+#include "JSByteArray.h"
+#include "JSClassRef.h"
+#include "JSFunction.h"
+#include "JSLock.h"
+#include "JSNotAnObject.h"
+#include "JSPropertyNameIterator.h"
+#include "JSStaticScopeObject.h"
+#include "Lexer.h"
+#include "Lookup.h"
+#include "Nodes.h"
+#include "ParserArena.h"
+#include "RegExpCache.h"
+#include "RegExpObject.h"
+#include "StrictEvalActivation.h"
+#include "StrongInlines.h"
+#include <wtf/Threading.h>
+#include <wtf/WTFThreadData.h>
+
+#if ENABLE(REGEXP_TRACING)
+#include "RegExp.h"
+#endif
+
+#if PLATFORM(MAC)
+#include <CoreFoundation/CoreFoundation.h>
+#endif
+
+using namespace WTF;
+
+namespace {
+
+using namespace JSC;
+
+class Recompiler : public MarkedBlock::VoidFunctor {
+public:
+ void operator()(JSCell*);
+};
+
+inline void Recompiler::operator()(JSCell* cell)
+{
+ if (!cell->inherits(&JSFunction::s_info))
+ return;
+ JSFunction* function = asFunction(cell);
+ if (!function->executable() || function->executable()->isHostFunction())
+ return;
+ function->jsExecutable()->discardCode();
+}
+
+} // namespace
+
+namespace JSC {
+
+extern const HashTable arrayConstructorTable;
+extern const HashTable arrayPrototypeTable;
+extern const HashTable booleanPrototypeTable;
+extern const HashTable jsonTable;
+extern const HashTable dateTable;
+extern const HashTable dateConstructorTable;
+extern const HashTable errorPrototypeTable;
+extern const HashTable globalObjectTable;
+extern const HashTable mathTable;
+extern const HashTable numberConstructorTable;
+extern const HashTable numberPrototypeTable;
+extern const HashTable objectConstructorTable;
+extern const HashTable objectPrototypeTable;
+extern const HashTable regExpTable;
+extern const HashTable regExpConstructorTable;
+extern const HashTable regExpPrototypeTable;
+extern const HashTable stringTable;
+extern const HashTable stringConstructorTable;
+
+JSGlobalData::JSGlobalData(GlobalDataType globalDataType, ThreadStackType threadStackType, HeapSize heapSize)
+ : globalDataType(globalDataType)
+ , clientData(0)
+ , topCallFrame(CallFrame::noCaller())
+ , arrayConstructorTable(fastNew<HashTable>(JSC::arrayConstructorTable))
+ , arrayPrototypeTable(fastNew<HashTable>(JSC::arrayPrototypeTable))
+ , booleanPrototypeTable(fastNew<HashTable>(JSC::booleanPrototypeTable))
+ , dateTable(fastNew<HashTable>(JSC::dateTable))
+ , dateConstructorTable(fastNew<HashTable>(JSC::dateConstructorTable))
+ , errorPrototypeTable(fastNew<HashTable>(JSC::errorPrototypeTable))
+ , globalObjectTable(fastNew<HashTable>(JSC::globalObjectTable))
+ , jsonTable(fastNew<HashTable>(JSC::jsonTable))
+ , mathTable(fastNew<HashTable>(JSC::mathTable))
+ , numberConstructorTable(fastNew<HashTable>(JSC::numberConstructorTable))
+ , numberPrototypeTable(fastNew<HashTable>(JSC::numberPrototypeTable))
+ , objectConstructorTable(fastNew<HashTable>(JSC::objectConstructorTable))
+ , objectPrototypeTable(fastNew<HashTable>(JSC::objectPrototypeTable))
+ , regExpTable(fastNew<HashTable>(JSC::regExpTable))
+ , regExpConstructorTable(fastNew<HashTable>(JSC::regExpConstructorTable))
+ , regExpPrototypeTable(fastNew<HashTable>(JSC::regExpPrototypeTable))
+ , stringTable(fastNew<HashTable>(JSC::stringTable))
+ , stringConstructorTable(fastNew<HashTable>(JSC::stringConstructorTable))
+ , identifierTable(globalDataType == Default ? wtfThreadData().currentIdentifierTable() : createIdentifierTable())
+ , propertyNames(new CommonIdentifiers(this))
+ , emptyList(new MarkedArgumentBuffer)
+#if ENABLE(ASSEMBLER)
+ , executableAllocator(*this)
+#endif
+ , parserArena(adoptPtr(new ParserArena))
+ , keywords(adoptPtr(new Keywords(this)))
+ , interpreter(0)
+ , heap(this, heapSize)
+#if ENABLE(DFG_JIT)
+ , sizeOfLastScratchBuffer(0)
+#endif
+ , dynamicGlobalObject(0)
+ , cachedUTCOffset(std::numeric_limits<double>::quiet_NaN())
+ , maxReentryDepth(threadStackType == ThreadStackTypeSmall ? MaxSmallThreadReentryDepth : MaxLargeThreadReentryDepth)
+ , m_regExpCache(new RegExpCache(this))
+#if ENABLE(REGEXP_TRACING)
+ , m_rtTraceList(new RTTraceList())
+#endif
+#ifndef NDEBUG
+ , exclusiveThread(0)
+#endif
+#if CPU(X86) && ENABLE(JIT)
+ , m_timeoutCount(512)
+#endif
+#if ENABLE(GC_VALIDATION)
+ , m_isInitializingObject(false)
+#endif
+{
+ interpreter = new Interpreter;
+ if (globalDataType == Default)
+ m_stack = wtfThreadData().stack();
+
+ // Need to be careful to keep everything consistent here
+ IdentifierTable* existingEntryIdentifierTable = wtfThreadData().setCurrentIdentifierTable(identifierTable);
+ JSLock lock(SilenceAssertionsOnly);
+ structureStructure.set(*this, Structure::createStructure(*this));
+ debuggerActivationStructure.set(*this, DebuggerActivation::createStructure(*this, 0, jsNull()));
+ activationStructure.set(*this, JSActivation::createStructure(*this, 0, jsNull()));
+ interruptedExecutionErrorStructure.set(*this, InterruptedExecutionError::createStructure(*this, 0, jsNull()));
+ terminatedExecutionErrorStructure.set(*this, TerminatedExecutionError::createStructure(*this, 0, jsNull()));
+ staticScopeStructure.set(*this, JSStaticScopeObject::createStructure(*this, 0, jsNull()));
+ strictEvalActivationStructure.set(*this, StrictEvalActivation::createStructure(*this, 0, jsNull()));
+ stringStructure.set(*this, JSString::createStructure(*this, 0, jsNull()));
+ notAnObjectStructure.set(*this, JSNotAnObject::createStructure(*this, 0, jsNull()));
+ propertyNameIteratorStructure.set(*this, JSPropertyNameIterator::createStructure(*this, 0, jsNull()));
+ getterSetterStructure.set(*this, GetterSetter::createStructure(*this, 0, jsNull()));
+ apiWrapperStructure.set(*this, JSAPIValueWrapper::createStructure(*this, 0, jsNull()));
+ scopeChainNodeStructure.set(*this, ScopeChainNode::createStructure(*this, 0, jsNull()));
+ executableStructure.set(*this, ExecutableBase::createStructure(*this, 0, jsNull()));
+ nativeExecutableStructure.set(*this, NativeExecutable::createStructure(*this, 0, jsNull()));
+ evalExecutableStructure.set(*this, EvalExecutable::createStructure(*this, 0, jsNull()));
+ programExecutableStructure.set(*this, ProgramExecutable::createStructure(*this, 0, jsNull()));
+ functionExecutableStructure.set(*this, FunctionExecutable::createStructure(*this, 0, jsNull()));
+ regExpStructure.set(*this, RegExp::createStructure(*this, 0, jsNull()));
+ structureChainStructure.set(*this, StructureChain::createStructure(*this, 0, jsNull()));
+
+ wtfThreadData().setCurrentIdentifierTable(existingEntryIdentifierTable);
+
+#if ENABLE(JIT) && ENABLE(INTERPRETER)
+#if USE(CF)
+ CFStringRef canUseJITKey = CFStringCreateWithCString(0 , "JavaScriptCoreUseJIT", kCFStringEncodingMacRoman);
+ CFBooleanRef canUseJIT = (CFBooleanRef)CFPreferencesCopyAppValue(canUseJITKey, kCFPreferencesCurrentApplication);
+ if (canUseJIT) {
+ m_canUseJIT = kCFBooleanTrue == canUseJIT;
+ CFRelease(canUseJIT);
+ } else {
+ char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+ m_canUseJIT = !canUseJITString || atoi(canUseJITString);
+ }
+ CFRelease(canUseJITKey);
+#elif OS(UNIX)
+ char* canUseJITString = getenv("JavaScriptCoreUseJIT");
+ m_canUseJIT = !canUseJITString || atoi(canUseJITString);
+#else
+ m_canUseJIT = true;
+#endif
+#endif
+#if ENABLE(JIT)
+#if ENABLE(INTERPRETER)
+ if (m_canUseJIT)
+ m_canUseJIT = executableAllocator.isValid();
+#endif
+ jitStubs = adoptPtr(new JITThunks(this));
+#endif
+
+ interpreter->initialize(this->canUseJIT());
+
+ heap.notifyIsSafeToCollect();
+}
+
+void JSGlobalData::clearBuiltinStructures()
+{
+ structureStructure.clear();
+ debuggerActivationStructure.clear();
+ activationStructure.clear();
+ interruptedExecutionErrorStructure.clear();
+ terminatedExecutionErrorStructure.clear();
+ staticScopeStructure.clear();
+ strictEvalActivationStructure.clear();
+ stringStructure.clear();
+ notAnObjectStructure.clear();
+ propertyNameIteratorStructure.clear();
+ getterSetterStructure.clear();
+ apiWrapperStructure.clear();
+ scopeChainNodeStructure.clear();
+ executableStructure.clear();
+ nativeExecutableStructure.clear();
+ evalExecutableStructure.clear();
+ programExecutableStructure.clear();
+ functionExecutableStructure.clear();
+ regExpStructure.clear();
+ structureChainStructure.clear();
+}
+
+JSGlobalData::~JSGlobalData()
+{
+ // By the time this is destroyed, heap.destroy() must already have been called.
+
+ delete interpreter;
+#ifndef NDEBUG
+ // Zeroing out to make the behavior more predictable when someone attempts to use a deleted instance.
+ interpreter = 0;
+#endif
+
+ arrayPrototypeTable->deleteTable();
+ arrayConstructorTable->deleteTable();
+ booleanPrototypeTable->deleteTable();
+ dateTable->deleteTable();
+ dateConstructorTable->deleteTable();
+ errorPrototypeTable->deleteTable();
+ globalObjectTable->deleteTable();
+ jsonTable->deleteTable();
+ mathTable->deleteTable();
+ numberConstructorTable->deleteTable();
+ numberPrototypeTable->deleteTable();
+ objectConstructorTable->deleteTable();
+ objectPrototypeTable->deleteTable();
+ regExpTable->deleteTable();
+ regExpConstructorTable->deleteTable();
+ regExpPrototypeTable->deleteTable();
+ stringTable->deleteTable();
+ stringConstructorTable->deleteTable();
+
+ fastDelete(const_cast<HashTable*>(arrayConstructorTable));
+ fastDelete(const_cast<HashTable*>(arrayPrototypeTable));
+ fastDelete(const_cast<HashTable*>(booleanPrototypeTable));
+ fastDelete(const_cast<HashTable*>(dateTable));
+ fastDelete(const_cast<HashTable*>(dateConstructorTable));
+ fastDelete(const_cast<HashTable*>(errorPrototypeTable));
+ fastDelete(const_cast<HashTable*>(globalObjectTable));
+ fastDelete(const_cast<HashTable*>(jsonTable));
+ fastDelete(const_cast<HashTable*>(mathTable));
+ fastDelete(const_cast<HashTable*>(numberConstructorTable));
+ fastDelete(const_cast<HashTable*>(numberPrototypeTable));
+ fastDelete(const_cast<HashTable*>(objectConstructorTable));
+ fastDelete(const_cast<HashTable*>(objectPrototypeTable));
+ fastDelete(const_cast<HashTable*>(regExpTable));
+ fastDelete(const_cast<HashTable*>(regExpConstructorTable));
+ fastDelete(const_cast<HashTable*>(regExpPrototypeTable));
+ fastDelete(const_cast<HashTable*>(stringTable));
+ fastDelete(const_cast<HashTable*>(stringConstructorTable));
+
+ opaqueJSClassData.clear();
+
+ delete emptyList;
+
+ delete propertyNames;
+ if (globalDataType != Default)
+ deleteIdentifierTable(identifierTable);
+
+ delete clientData;
+ delete m_regExpCache;
+#if ENABLE(REGEXP_TRACING)
+ delete m_rtTraceList;
+#endif
+
+#if ENABLE(DFG_JIT)
+ for (unsigned i = 0; i < scratchBuffers.size(); ++i)
+ fastFree(scratchBuffers[i]);
+#endif
+}
+
+PassRefPtr<JSGlobalData> JSGlobalData::createContextGroup(ThreadStackType type, HeapSize heapSize)
+{
+ return adoptRef(new JSGlobalData(APIContextGroup, type, heapSize));
+}
+
+PassRefPtr<JSGlobalData> JSGlobalData::create(ThreadStackType type, HeapSize heapSize)
+{
+ return adoptRef(new JSGlobalData(Default, type, heapSize));
+}
+
+PassRefPtr<JSGlobalData> JSGlobalData::createLeaked(ThreadStackType type, HeapSize heapSize)
+{
+ return create(type, heapSize);
+}
+
+bool JSGlobalData::sharedInstanceExists()
+{
+ return sharedInstanceInternal();
+}
+
+JSGlobalData& JSGlobalData::sharedInstance()
+{
+ JSGlobalData*& instance = sharedInstanceInternal();
+ if (!instance) {
+ instance = adoptRef(new JSGlobalData(APIShared, ThreadStackTypeSmall, SmallHeap)).leakRef();
+ instance->makeUsableFromMultipleThreads();
+ }
+ return *instance;
+}
+
+JSGlobalData*& JSGlobalData::sharedInstanceInternal()
+{
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ static JSGlobalData* sharedInstance;
+ return sharedInstance;
+}
+
+#if ENABLE(JIT)
+static ThunkGenerator thunkGeneratorForIntrinsic(Intrinsic intrinsic)
+{
+ switch (intrinsic) {
+ case CharCodeAtIntrinsic:
+ return charCodeAtThunkGenerator;
+ case CharAtIntrinsic:
+ return charAtThunkGenerator;
+ case FromCharCodeIntrinsic:
+ return fromCharCodeThunkGenerator;
+ case SqrtIntrinsic:
+ return sqrtThunkGenerator;
+ case PowIntrinsic:
+ return powThunkGenerator;
+ case AbsIntrinsic:
+ return absThunkGenerator;
+ case FloorIntrinsic:
+ return floorThunkGenerator;
+ case CeilIntrinsic:
+ return ceilThunkGenerator;
+ case RoundIntrinsic:
+ return roundThunkGenerator;
+ case ExpIntrinsic:
+ return expThunkGenerator;
+ case LogIntrinsic:
+ return logThunkGenerator;
+ default:
+ return 0;
+ }
+}
+
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
+{
+#if ENABLE(INTERPRETER)
+ if (!canUseJIT())
+ return NativeExecutable::create(*this, function, constructor);
+#endif
+ return jitStubs->hostFunctionStub(this, function, constructor);
+}
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, Intrinsic intrinsic)
+{
+ ASSERT(canUseJIT());
+ return jitStubs->hostFunctionStub(this, function, intrinsic != NoIntrinsic ? thunkGeneratorForIntrinsic(intrinsic) : 0, intrinsic);
+}
+#else
+NativeExecutable* JSGlobalData::getHostFunction(NativeFunction function, NativeFunction constructor)
+{
+ return NativeExecutable::create(*this, function, constructor);
+}
+#endif
+
+JSGlobalData::ClientData::~ClientData()
+{
+}
+
+void JSGlobalData::resetDateCache()
+{
+ cachedUTCOffset = std::numeric_limits<double>::quiet_NaN();
+ dstOffsetCache.reset();
+ cachedDateString = UString();
+ cachedDateStringValue = std::numeric_limits<double>::quiet_NaN();
+ dateInstanceCache.reset();
+}
+
+void JSGlobalData::startSampling()
+{
+ interpreter->startSampling();
+}
+
+void JSGlobalData::stopSampling()
+{
+ interpreter->stopSampling();
+}
+
+void JSGlobalData::dumpSampleData(ExecState* exec)
+{
+ interpreter->dumpSampleData(exec);
+#if ENABLE(ASSEMBLER)
+ ExecutableAllocator::dumpProfile();
+#endif
+}
+
+void JSGlobalData::recompileAllJSFunctions()
+{
+ // If JavaScript is running, it's not safe to recompile, since we'll end
+ // up throwing away code that is live on the stack.
+ ASSERT(!dynamicGlobalObject);
+
+ heap.objectSpace().forEachCell<Recompiler>();
+}
+
+struct StackPreservingRecompiler : public MarkedBlock::VoidFunctor {
+ HashSet<FunctionExecutable*> currentlyExecutingFunctions;
+ void operator()(JSCell* cell)
+ {
+ if (!cell->inherits(&FunctionExecutable::s_info))
+ return;
+ FunctionExecutable* executable = jsCast<FunctionExecutable*>(cell);
+ if (currentlyExecutingFunctions.contains(executable))
+ return;
+ executable->discardCode();
+ }
+};
+
+void JSGlobalData::releaseExecutableMemory()
+{
+ if (dynamicGlobalObject) {
+ StackPreservingRecompiler recompiler;
+ HashSet<JSCell*> roots;
+ heap.getConservativeRegisterRoots(roots);
+ HashSet<JSCell*>::iterator end = roots.end();
+ for (HashSet<JSCell*>::iterator ptr = roots.begin(); ptr != end; ++ptr) {
+ ScriptExecutable* executable = 0;
+ JSCell* cell = *ptr;
+ if (cell->inherits(&ScriptExecutable::s_info))
+ executable = static_cast<ScriptExecutable*>(*ptr);
+ else if (cell->inherits(&JSFunction::s_info)) {
+ JSFunction* function = asFunction(*ptr);
+ if (function->isHostFunction())
+ continue;
+ executable = function->jsExecutable();
+ } else
+ continue;
+ ASSERT(executable->inherits(&ScriptExecutable::s_info));
+ executable->unlinkCalls();
+ if (executable->inherits(&FunctionExecutable::s_info))
+ recompiler.currentlyExecutingFunctions.add(static_cast<FunctionExecutable*>(executable));
+
+ }
+ heap.objectSpace().forEachCell<StackPreservingRecompiler>(recompiler);
+ }
+ m_regExpCache->invalidateCode();
+ heap.collectAllGarbage();
+}
+
+void releaseExecutableMemory(JSGlobalData& globalData)
+{
+ globalData.releaseExecutableMemory();
+}
+
+#if ENABLE(REGEXP_TRACING)
+void JSGlobalData::addRegExpToTrace(RegExp* regExp)
+{
+ m_rtTraceList->add(regExp);
+}
+
+void JSGlobalData::dumpRegExpTrace()
+{
+ // The first RegExp object is ignored. It is create by the RegExpPrototype ctor and not used.
+ RTTraceList::iterator iter = ++m_rtTraceList->begin();
+
+ if (iter != m_rtTraceList->end()) {
+ printf("\nRegExp Tracing\n");
+ printf(" match() matches\n");
+ printf("Regular Expression JIT Address calls found\n");
+ printf("----------------------------------------+----------------+----------+----------\n");
+
+ unsigned reCount = 0;
+
+ for (; iter != m_rtTraceList->end(); ++iter, ++reCount)
+ (*iter)->printTraceData();
+
+ printf("%d Regular Expressions\n", reCount);
+ }
+
+ m_rtTraceList->clear();
+}
+#else
+void JSGlobalData::dumpRegExpTrace()
+{
+}
+#endif
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalData.h b/Source/JavaScriptCore/runtime/JSGlobalData.h
new file mode 100644
index 000000000..1619f9297
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalData.h
@@ -0,0 +1,386 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSGlobalData_h
+#define JSGlobalData_h
+
+#include "CachedTranscendentalFunction.h"
+#include "Intrinsic.h"
+#include "DateInstanceCache.h"
+#include "ExecutableAllocator.h"
+#include "Heap.h"
+#include "Strong.h"
+#include "JITStubs.h"
+#include "JSValue.h"
+#include "NumericStrings.h"
+#include "SmallStrings.h"
+#include "Terminator.h"
+#include "TimeoutChecker.h"
+#include "WeakRandom.h"
+#include <wtf/BumpPointerAllocator.h>
+#include <wtf/Forward.h>
+#include <wtf/HashMap.h>
+#include <wtf/RefCounted.h>
+#include <wtf/ThreadSpecific.h>
+#include <wtf/WTFThreadData.h>
+#if ENABLE(REGEXP_TRACING)
+#include <wtf/ListHashSet.h>
+#endif
+
+struct OpaqueJSClass;
+struct OpaqueJSClassContextData;
+
+namespace JSC {
+
+ class CodeBlock;
+ class CommonIdentifiers;
+ class HandleStack;
+ class IdentifierTable;
+ class Interpreter;
+ class JSGlobalObject;
+ class JSObject;
+ class Keywords;
+ class NativeExecutable;
+ class ParserArena;
+ class RegExpCache;
+ class Stringifier;
+ class Structure;
+ class UString;
+#if ENABLE(REGEXP_TRACING)
+ class RegExp;
+#endif
+
+ struct HashTable;
+ struct Instruction;
+
+ struct DSTOffsetCache {
+ DSTOffsetCache()
+ {
+ reset();
+ }
+
+ void reset()
+ {
+ offset = 0.0;
+ start = 0.0;
+ end = -1.0;
+ increment = 0.0;
+ }
+
+ double offset;
+ double start;
+ double end;
+ double increment;
+ };
+
+ enum ThreadStackType {
+ ThreadStackTypeLarge,
+ ThreadStackTypeSmall
+ };
+
+ struct TypedArrayDescriptor {
+ TypedArrayDescriptor()
+ : m_classInfo(0)
+ , m_storageOffset(0)
+ , m_lengthOffset(0)
+ {
+ }
+ TypedArrayDescriptor(const ClassInfo* classInfo, size_t storageOffset, size_t lengthOffset)
+ : m_classInfo(classInfo)
+ , m_storageOffset(storageOffset)
+ , m_lengthOffset(lengthOffset)
+ {
+ }
+ const ClassInfo* m_classInfo;
+ size_t m_storageOffset;
+ size_t m_lengthOffset;
+ };
+
+ class JSGlobalData : public RefCounted<JSGlobalData> {
+ public:
+ // WebCore has a one-to-one mapping of threads to JSGlobalDatas;
+ // either create() or createLeaked() should only be called once
+ // on a thread, this is the 'default' JSGlobalData (it uses the
+ // thread's default string uniquing table from wtfThreadData).
+ // API contexts created using the new context group aware interface
+ // create APIContextGroup objects which require less locking of JSC
+ // than the old singleton APIShared JSGlobalData created for use by
+ // the original API.
+ enum GlobalDataType { Default, APIContextGroup, APIShared };
+
+ struct ClientData {
+ virtual ~ClientData() = 0;
+ };
+
+ bool isSharedInstance() { return globalDataType == APIShared; }
+ bool usingAPI() { return globalDataType != Default; }
+ static bool sharedInstanceExists();
+ static JSGlobalData& sharedInstance();
+
+ static PassRefPtr<JSGlobalData> create(ThreadStackType, HeapSize = SmallHeap);
+ static PassRefPtr<JSGlobalData> createLeaked(ThreadStackType, HeapSize = SmallHeap);
+ static PassRefPtr<JSGlobalData> createContextGroup(ThreadStackType, HeapSize = SmallHeap);
+ ~JSGlobalData();
+
+ void makeUsableFromMultipleThreads() { heap.machineThreads().makeUsableFromMultipleThreads(); }
+
+ GlobalDataType globalDataType;
+ ClientData* clientData;
+ CallFrame* topCallFrame;
+
+ const HashTable* arrayConstructorTable;
+ const HashTable* arrayPrototypeTable;
+ const HashTable* booleanPrototypeTable;
+ const HashTable* dateTable;
+ const HashTable* dateConstructorTable;
+ const HashTable* errorPrototypeTable;
+ const HashTable* globalObjectTable;
+ const HashTable* jsonTable;
+ const HashTable* mathTable;
+ const HashTable* numberConstructorTable;
+ const HashTable* numberPrototypeTable;
+ const HashTable* objectConstructorTable;
+ const HashTable* objectPrototypeTable;
+ const HashTable* regExpTable;
+ const HashTable* regExpConstructorTable;
+ const HashTable* regExpPrototypeTable;
+ const HashTable* stringTable;
+ const HashTable* stringConstructorTable;
+
+ Strong<Structure> structureStructure;
+ Strong<Structure> debuggerActivationStructure;
+ Strong<Structure> activationStructure;
+ Strong<Structure> interruptedExecutionErrorStructure;
+ Strong<Structure> terminatedExecutionErrorStructure;
+ Strong<Structure> staticScopeStructure;
+ Strong<Structure> strictEvalActivationStructure;
+ Strong<Structure> stringStructure;
+ Strong<Structure> notAnObjectStructure;
+ Strong<Structure> propertyNameIteratorStructure;
+ Strong<Structure> getterSetterStructure;
+ Strong<Structure> apiWrapperStructure;
+ Strong<Structure> scopeChainNodeStructure;
+ Strong<Structure> executableStructure;
+ Strong<Structure> nativeExecutableStructure;
+ Strong<Structure> evalExecutableStructure;
+ Strong<Structure> programExecutableStructure;
+ Strong<Structure> functionExecutableStructure;
+ Strong<Structure> regExpStructure;
+ Strong<Structure> structureChainStructure;
+
+ IdentifierTable* identifierTable;
+ CommonIdentifiers* propertyNames;
+ const MarkedArgumentBuffer* emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark.
+ SmallStrings smallStrings;
+ NumericStrings numericStrings;
+ DateInstanceCache dateInstanceCache;
+ Vector<CodeBlock*> codeBlocksBeingCompiled;
+ void startedCompiling(CodeBlock* codeBlock)
+ {
+ codeBlocksBeingCompiled.append(codeBlock);
+ }
+
+ void finishedCompiling(CodeBlock* codeBlock)
+ {
+ ASSERT_UNUSED(codeBlock, codeBlock == codeBlocksBeingCompiled.last());
+ codeBlocksBeingCompiled.removeLast();
+ }
+
+#if ENABLE(ASSEMBLER)
+ ExecutableAllocator executableAllocator;
+#endif
+
+#if !ENABLE(JIT)
+ bool canUseJIT() { return false; } // interpreter only
+#elif !ENABLE(INTERPRETER)
+ bool canUseJIT() { return true; } // jit only
+#else
+ bool canUseJIT() { return m_canUseJIT; }
+#endif
+
+ const StackBounds& stack()
+ {
+ return (globalDataType == Default)
+ ? m_stack
+ : wtfThreadData().stack();
+ }
+
+ OwnPtr<ParserArena> parserArena;
+ OwnPtr<Keywords> keywords;
+ Interpreter* interpreter;
+#if ENABLE(JIT)
+ OwnPtr<JITThunks> jitStubs;
+ MacroAssemblerCodeRef getCTIStub(ThunkGenerator generator)
+ {
+ return jitStubs->ctiStub(this, generator);
+ }
+ NativeExecutable* getHostFunction(NativeFunction, Intrinsic);
+#endif
+ NativeExecutable* getHostFunction(NativeFunction, NativeFunction constructor);
+
+ TimeoutChecker timeoutChecker;
+ Terminator terminator;
+ Heap heap;
+
+ JSValue exception;
+#if ENABLE(JIT)
+ ReturnAddressPtr exceptionLocation;
+ JSValue hostCallReturnValue;
+#if ENABLE(DFG_JIT)
+ uint32_t osrExitIndex;
+ void* osrExitJumpDestination;
+ Vector<void*> scratchBuffers;
+ size_t sizeOfLastScratchBuffer;
+
+ void* scratchBufferForSize(size_t size)
+ {
+ if (!size)
+ return 0;
+
+ if (size > sizeOfLastScratchBuffer) {
+ // Protect against a N^2 memory usage pathology by ensuring
+ // that at worst, we get a geometric series, meaning that the
+ // total memory usage is somewhere around
+ // max(scratch buffer size) * 4.
+ sizeOfLastScratchBuffer = size * 2;
+
+ scratchBuffers.append(fastMalloc(sizeOfLastScratchBuffer));
+ }
+
+ return scratchBuffers.last();
+ }
+#endif
+#endif
+
+ HashMap<OpaqueJSClass*, OwnPtr<OpaqueJSClassContextData> > opaqueJSClassData;
+
+ JSGlobalObject* dynamicGlobalObject;
+
+ HashSet<JSObject*> stringRecursionCheckVisitedObjects;
+
+ double cachedUTCOffset;
+ DSTOffsetCache dstOffsetCache;
+
+ UString cachedDateString;
+ double cachedDateStringValue;
+
+ int maxReentryDepth;
+
+ RegExpCache* m_regExpCache;
+ BumpPointerAllocator m_regExpAllocator;
+
+#if ENABLE(REGEXP_TRACING)
+ typedef ListHashSet<RefPtr<RegExp> > RTTraceList;
+ RTTraceList* m_rtTraceList;
+#endif
+
+#ifndef NDEBUG
+ ThreadIdentifier exclusiveThread;
+#endif
+
+ CachedTranscendentalFunction<sin> cachedSin;
+
+ void resetDateCache();
+
+ void startSampling();
+ void stopSampling();
+ void dumpSampleData(ExecState* exec);
+ void recompileAllJSFunctions();
+ RegExpCache* regExpCache() { return m_regExpCache; }
+#if ENABLE(REGEXP_TRACING)
+ void addRegExpToTrace(PassRefPtr<RegExp> regExp);
+#endif
+ void dumpRegExpTrace();
+ void clearBuiltinStructures();
+
+ bool isCollectorBusy() { return heap.isBusy(); }
+ void releaseExecutableMemory();
+
+#if ENABLE(GC_VALIDATION)
+ bool isInitializingObject() const;
+ void setInitializingObject(bool);
+#endif
+
+#if CPU(X86) && ENABLE(JIT)
+ unsigned m_timeoutCount;
+#endif
+
+#define registerTypedArrayFunction(type, capitalizedType) \
+ void registerTypedArrayDescriptor(const capitalizedType##Array*, const TypedArrayDescriptor& descriptor) \
+ { \
+ ASSERT(!m_##type##ArrayDescriptor.m_classInfo || m_##type##ArrayDescriptor.m_classInfo == descriptor.m_classInfo); \
+ m_##type##ArrayDescriptor = descriptor; \
+ } \
+ const TypedArrayDescriptor& type##ArrayDescriptor() const { return m_##type##ArrayDescriptor; }
+
+ registerTypedArrayFunction(int8, Int8);
+ registerTypedArrayFunction(int16, Int16);
+ registerTypedArrayFunction(int32, Int32);
+ registerTypedArrayFunction(uint8, Uint8);
+ registerTypedArrayFunction(uint16, Uint16);
+ registerTypedArrayFunction(uint32, Uint32);
+ registerTypedArrayFunction(float32, Float32);
+ registerTypedArrayFunction(float64, Float64);
+#undef registerTypedArrayFunction
+
+ private:
+ JSGlobalData(GlobalDataType, ThreadStackType, HeapSize);
+ static JSGlobalData*& sharedInstanceInternal();
+ void createNativeThunk();
+#if ENABLE(JIT) && ENABLE(INTERPRETER)
+ bool m_canUseJIT;
+#endif
+ StackBounds m_stack;
+#if ENABLE(GC_VALIDATION)
+ bool m_isInitializingObject;
+#endif
+ TypedArrayDescriptor m_int8ArrayDescriptor;
+ TypedArrayDescriptor m_int16ArrayDescriptor;
+ TypedArrayDescriptor m_int32ArrayDescriptor;
+ TypedArrayDescriptor m_uint8ArrayDescriptor;
+ TypedArrayDescriptor m_uint16ArrayDescriptor;
+ TypedArrayDescriptor m_uint32ArrayDescriptor;
+ TypedArrayDescriptor m_float32ArrayDescriptor;
+ TypedArrayDescriptor m_float64ArrayDescriptor;
+ };
+
+#if ENABLE(GC_VALIDATION)
+ inline bool JSGlobalData::isInitializingObject() const
+ {
+ return m_isInitializingObject;
+ }
+
+ inline void JSGlobalData::setInitializingObject(bool initializingObject)
+ {
+ m_isInitializingObject = initializingObject;
+ }
+#endif
+
+} // namespace JSC
+
+#endif // JSGlobalData_h
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.cpp b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
new file mode 100644
index 000000000..5ad53c222
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.cpp
@@ -0,0 +1,482 @@
+/*
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSGlobalObject.h"
+
+#include "JSCallbackConstructor.h"
+#include "JSCallbackFunction.h"
+#include "JSCallbackObject.h"
+
+#include "Arguments.h"
+#include "ArrayConstructor.h"
+#include "ArrayPrototype.h"
+#include "BooleanConstructor.h"
+#include "BooleanPrototype.h"
+#include "CodeBlock.h"
+#include "DateConstructor.h"
+#include "DatePrototype.h"
+#include "Error.h"
+#include "ErrorConstructor.h"
+#include "ErrorPrototype.h"
+#include "FunctionConstructor.h"
+#include "FunctionPrototype.h"
+#include "GetterSetter.h"
+#include "JSBoundFunction.h"
+#include "JSFunction.h"
+#include "JSGlobalObjectFunctions.h"
+#include "JSLock.h"
+#include "JSONObject.h"
+#include "Interpreter.h"
+#include "Lookup.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 "RegExpConstructor.h"
+#include "RegExpMatchesArray.h"
+#include "RegExpObject.h"
+#include "RegExpPrototype.h"
+#include "ScopeChainMark.h"
+#include "StringConstructor.h"
+#include "StringPrototype.h"
+#include "Debugger.h"
+
+#include "JSGlobalObject.lut.h"
+
+namespace JSC {
+
+const ClassInfo JSGlobalObject::s_info = { "GlobalObject", &JSVariableObject::s_info, 0, ExecState::globalObjectTable, CREATE_METHOD_TABLE(JSGlobalObject) };
+
+const GlobalObjectMethodTable JSGlobalObject::s_globalObjectMethodTable = { &supportsProfiling, &supportsRichSourceInfo, &shouldInterruptScript };
+
+/* Source for JSGlobalObject.lut.h
+@begin globalObjectTable
+ parseInt globalFuncParseInt DontEnum|Function 2
+ parseFloat globalFuncParseFloat DontEnum|Function 1
+ isNaN globalFuncIsNaN DontEnum|Function 1
+ isFinite globalFuncIsFinite DontEnum|Function 1
+ escape globalFuncEscape DontEnum|Function 1
+ unescape globalFuncUnescape DontEnum|Function 1
+ decodeURI globalFuncDecodeURI DontEnum|Function 1
+ decodeURIComponent globalFuncDecodeURIComponent DontEnum|Function 1
+ encodeURI globalFuncEncodeURI DontEnum|Function 1
+ encodeURIComponent globalFuncEncodeURIComponent DontEnum|Function 1
+@end
+*/
+
+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;
+
+template <typename T> static inline void visitIfNeeded(SlotVisitor& visitor, WriteBarrier<T>* v)
+{
+ if (*v)
+ visitor.append(v);
+}
+
+JSGlobalObject::~JSGlobalObject()
+{
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ if (m_debugger)
+ m_debugger->detach(this);
+
+ Profiler** profiler = Profiler::enabledProfilerReference();
+ if (UNLIKELY(*profiler != 0)) {
+ (*profiler)->stopProfiling(this);
+ }
+}
+
+void JSGlobalObject::destroy(JSCell* cell)
+{
+ jsCast<JSGlobalObject*>(cell)->JSGlobalObject::~JSGlobalObject();
+}
+
+void JSGlobalObject::init(JSObject* thisValue)
+{
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ structure()->disableSpecificFunctionTracking();
+
+ m_globalData = Heap::heap(this)->globalData();
+ m_globalScopeChain.set(*m_globalData, this, ScopeChainNode::create(0, this, m_globalData.get(), this, thisValue));
+
+ JSGlobalObject::globalExec()->init(0, 0, m_globalScopeChain.get(), CallFrame::noCaller(), 0, 0);
+
+ m_debugger = 0;
+
+ reset(prototype());
+}
+
+void JSGlobalObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+
+ if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode()))
+ return;
+ JSVariableObject::put(thisObject, exec, propertyName, value, slot);
+}
+
+void JSGlobalObject::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+
+ if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes))
+ return;
+
+ JSValue valueBefore = thisObject->getDirect(exec->globalData(), propertyName);
+ PutPropertySlot slot;
+ JSVariableObject::put(thisObject, exec, propertyName, value, slot);
+ if (!valueBefore) {
+ JSValue valueAfter = thisObject->getDirect(exec->globalData(), propertyName);
+ if (valueAfter)
+ JSObject::putWithAttributes(thisObject, exec, propertyName, valueAfter, attributes);
+ }
+}
+
+void JSGlobalObject::defineGetter(JSObject* object, ExecState* exec, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes)
+{
+ JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object);
+ PropertySlot slot;
+ if (!thisObject->symbolTableGet(propertyName, slot))
+ JSVariableObject::defineGetter(thisObject, exec, propertyName, getterFunc, attributes);
+}
+
+void JSGlobalObject::defineSetter(JSObject* object, ExecState* exec, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes)
+{
+ JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object);
+ PropertySlot slot;
+ if (!thisObject->symbolTableGet(propertyName, slot))
+ JSVariableObject::defineSetter(thisObject, exec, propertyName, setterFunc, attributes);
+}
+
+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();
+
+ m_functionPrototype.set(exec->globalData(), this, FunctionPrototype::create(exec, this, FunctionPrototype::createStructure(exec->globalData(), this, jsNull()))); // The real prototype will be set once ObjectPrototype is created.
+ m_functionStructure.set(exec->globalData(), this, JSFunction::createStructure(exec->globalData(), this, m_functionPrototype.get()));
+ m_boundFunctionStructure.set(exec->globalData(), this, JSBoundFunction::createStructure(exec->globalData(), this, m_functionPrototype.get()));
+ m_namedFunctionStructure.set(exec->globalData(), this, Structure::addPropertyTransition(exec->globalData(), m_functionStructure.get(), exec->globalData().propertyNames->name, DontDelete | ReadOnly | DontEnum, 0, m_functionNameOffset));
+ m_internalFunctionStructure.set(exec->globalData(), this, InternalFunction::createStructure(exec->globalData(), this, m_functionPrototype.get()));
+ JSFunction* callFunction = 0;
+ JSFunction* applyFunction = 0;
+ m_functionPrototype->addFunctionProperties(exec, this, &callFunction, &applyFunction);
+ m_callFunction.set(exec->globalData(), this, callFunction);
+ m_applyFunction.set(exec->globalData(), this, applyFunction);
+ m_objectPrototype.set(exec->globalData(), this, ObjectPrototype::create(exec, this, ObjectPrototype::createStructure(exec->globalData(), this, jsNull())));
+ m_functionPrototype->structure()->setPrototypeWithoutTransition(exec->globalData(), m_objectPrototype.get());
+
+ m_emptyObjectStructure.set(exec->globalData(), this, m_objectPrototype->inheritorID(exec->globalData()));
+ m_nullPrototypeObjectStructure.set(exec->globalData(), this, createEmptyObjectStructure(exec->globalData(), this, jsNull()));
+
+ m_callbackFunctionStructure.set(exec->globalData(), this, JSCallbackFunction::createStructure(exec->globalData(), this, m_functionPrototype.get()));
+ m_argumentsStructure.set(exec->globalData(), this, Arguments::createStructure(exec->globalData(), this, m_objectPrototype.get()));
+ m_callbackConstructorStructure.set(exec->globalData(), this, JSCallbackConstructor::createStructure(exec->globalData(), this, m_objectPrototype.get()));
+ m_callbackObjectStructure.set(exec->globalData(), this, JSCallbackObject<JSNonFinalObject>::createStructure(exec->globalData(), this, m_objectPrototype.get()));
+
+ m_arrayPrototype.set(exec->globalData(), this, ArrayPrototype::create(exec, this, ArrayPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
+ m_arrayStructure.set(exec->globalData(), this, JSArray::createStructure(exec->globalData(), this, m_arrayPrototype.get()));
+ m_regExpMatchesArrayStructure.set(exec->globalData(), this, RegExpMatchesArray::createStructure(exec->globalData(), this, m_arrayPrototype.get()));
+
+ m_stringPrototype.set(exec->globalData(), this, StringPrototype::create(exec, this, StringPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
+ m_stringObjectStructure.set(exec->globalData(), this, StringObject::createStructure(exec->globalData(), this, m_stringPrototype.get()));
+
+ m_booleanPrototype.set(exec->globalData(), this, BooleanPrototype::create(exec, this, BooleanPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
+ m_booleanObjectStructure.set(exec->globalData(), this, BooleanObject::createStructure(exec->globalData(), this, m_booleanPrototype.get()));
+
+ m_numberPrototype.set(exec->globalData(), this, NumberPrototype::create(exec, this, NumberPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
+ m_numberObjectStructure.set(exec->globalData(), this, NumberObject::createStructure(exec->globalData(), this, m_numberPrototype.get()));
+
+ m_datePrototype.set(exec->globalData(), this, DatePrototype::create(exec, this, DatePrototype::createStructure(exec->globalData(), this, m_objectPrototype.get())));
+ m_dateStructure.set(exec->globalData(), this, DateInstance::createStructure(exec->globalData(), this, m_datePrototype.get()));
+
+ RegExp* emptyRegex = RegExp::create(exec->globalData(), "", NoFlags);
+
+ m_regExpPrototype.set(exec->globalData(), this, RegExpPrototype::create(exec, this, RegExpPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()), emptyRegex));
+ m_regExpStructure.set(exec->globalData(), this, RegExpObject::createStructure(exec->globalData(), this, m_regExpPrototype.get()));
+
+ m_methodCallDummy.set(exec->globalData(), this, constructEmptyObject(exec));
+
+ ErrorPrototype* errorPrototype = ErrorPrototype::create(exec, this, ErrorPrototype::createStructure(exec->globalData(), this, m_objectPrototype.get()));
+ m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), this, errorPrototype));
+
+ // Constructors
+
+ JSCell* objectConstructor = ObjectConstructor::create(exec, this, ObjectConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_objectPrototype.get());
+ JSCell* functionConstructor = FunctionConstructor::create(exec, this, FunctionConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_functionPrototype.get());
+ JSCell* arrayConstructor = ArrayConstructor::create(exec, this, ArrayConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_arrayPrototype.get());
+ JSCell* stringConstructor = StringConstructor::create(exec, this, StringConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_stringPrototype.get());
+ JSCell* booleanConstructor = BooleanConstructor::create(exec, this, BooleanConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_booleanPrototype.get());
+ JSCell* numberConstructor = NumberConstructor::create(exec, this, NumberConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_numberPrototype.get());
+ JSCell* dateConstructor = DateConstructor::create(exec, this, DateConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_datePrototype.get());
+
+ m_regExpConstructor.set(exec->globalData(), this, RegExpConstructor::create(exec, this, RegExpConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), m_regExpPrototype.get()));
+
+ m_errorConstructor.set(exec->globalData(), this, ErrorConstructor::create(exec, this, ErrorConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get()), errorPrototype));
+
+ Structure* nativeErrorPrototypeStructure = NativeErrorPrototype::createStructure(exec->globalData(), this, errorPrototype);
+ Structure* nativeErrorStructure = NativeErrorConstructor::createStructure(exec->globalData(), this, m_functionPrototype.get());
+ m_evalErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "EvalError"));
+ m_rangeErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "RangeError"));
+ m_referenceErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "ReferenceError"));
+ m_syntaxErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "SyntaxError"));
+ m_typeErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "TypeError"));
+ m_URIErrorConstructor.set(exec->globalData(), this, NativeErrorConstructor::create(exec, this, nativeErrorStructure, nativeErrorPrototypeStructure, "URIError"));
+
+ m_objectPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, objectConstructor, DontEnum);
+ m_functionPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, functionConstructor, DontEnum);
+ m_arrayPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, arrayConstructor, DontEnum);
+ m_booleanPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, booleanConstructor, DontEnum);
+ m_stringPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, stringConstructor, DontEnum);
+ m_numberPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, numberConstructor, DontEnum);
+ m_datePrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, dateConstructor, DontEnum);
+ m_regExpPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_regExpConstructor.get(), DontEnum);
+ errorPrototype->putDirectWithoutTransition(exec->globalData(), exec->propertyNames().constructor, m_errorConstructor.get(), DontEnum);
+
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Object"), objectConstructor, DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Function"), functionConstructor, DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Array"), arrayConstructor, DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Boolean"), booleanConstructor, DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "String"), stringConstructor, DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Number"), numberConstructor, DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Date"), dateConstructor, DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "RegExp"), m_regExpConstructor.get(), DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "Error"), m_errorConstructor.get(), DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "EvalError"), m_evalErrorConstructor.get(), DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "RangeError"), m_rangeErrorConstructor.get(), DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "ReferenceError"), m_referenceErrorConstructor.get(), DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "SyntaxError"), m_syntaxErrorConstructor.get(), DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "TypeError"), m_typeErrorConstructor.get(), DontEnum);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "URIError"), m_URIErrorConstructor.get(), DontEnum);
+
+ m_evalFunction.set(exec->globalData(), this, JSFunction::create(exec, this, 1, exec->propertyNames().eval, globalFuncEval));
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().eval, m_evalFunction.get(), DontEnum);
+
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "JSON"), JSONObject::create(exec, this, JSONObject::createStructure(exec->globalData(), this, m_objectPrototype.get())), DontEnum);
+
+ GlobalPropertyInfo staticGlobals[] = {
+ GlobalPropertyInfo(Identifier(exec, "Math"), MathObject::create(exec, this, MathObject::createStructure(exec->globalData(), this, m_objectPrototype.get())), DontEnum | DontDelete),
+ GlobalPropertyInfo(Identifier(exec, "NaN"), jsNaN(), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(Identifier(exec, "Infinity"), jsNumber(std::numeric_limits<double>::infinity()), DontEnum | DontDelete | ReadOnly),
+ GlobalPropertyInfo(Identifier(exec, "undefined"), jsUndefined(), DontEnum | DontDelete | ReadOnly)
+ };
+ addStaticGlobals(staticGlobals, WTF_ARRAY_LENGTH(staticGlobals));
+
+ resetPrototype(exec->globalData(), prototype);
+}
+
+void JSGlobalObject::createThrowTypeError(ExecState* exec)
+{
+ JSFunction* thrower = JSFunction::create(exec, this, 0, Identifier(), globalFuncThrowTypeError);
+ GetterSetter* getterSetter = GetterSetter::create(exec);
+ getterSetter->setGetter(exec->globalData(), thrower);
+ getterSetter->setSetter(exec->globalData(), thrower);
+ m_throwTypeErrorGetterSetter.set(exec->globalData(), this, getterSetter);
+}
+
+// Set prototype, and also insert the object prototype at the end of the chain.
+void JSGlobalObject::resetPrototype(JSGlobalData& globalData, JSValue prototype)
+{
+ setPrototype(globalData, prototype);
+
+ JSObject* oldLastInPrototypeChain = lastInPrototypeChain(this);
+ JSObject* objectPrototype = m_objectPrototype.get();
+ if (oldLastInPrototypeChain != objectPrototype)
+ oldLastInPrototypeChain->setPrototype(globalData, objectPrototype);
+}
+
+void JSGlobalObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ JSVariableObject::visitChildren(thisObject, visitor);
+
+ visitIfNeeded(visitor, &thisObject->m_globalScopeChain);
+ visitIfNeeded(visitor, &thisObject->m_methodCallDummy);
+
+ visitIfNeeded(visitor, &thisObject->m_regExpConstructor);
+ visitIfNeeded(visitor, &thisObject->m_errorConstructor);
+ visitIfNeeded(visitor, &thisObject->m_evalErrorConstructor);
+ visitIfNeeded(visitor, &thisObject->m_rangeErrorConstructor);
+ visitIfNeeded(visitor, &thisObject->m_referenceErrorConstructor);
+ visitIfNeeded(visitor, &thisObject->m_syntaxErrorConstructor);
+ visitIfNeeded(visitor, &thisObject->m_typeErrorConstructor);
+ visitIfNeeded(visitor, &thisObject->m_URIErrorConstructor);
+
+ visitIfNeeded(visitor, &thisObject->m_evalFunction);
+ visitIfNeeded(visitor, &thisObject->m_callFunction);
+ visitIfNeeded(visitor, &thisObject->m_applyFunction);
+ visitIfNeeded(visitor, &thisObject->m_throwTypeErrorGetterSetter);
+
+ visitIfNeeded(visitor, &thisObject->m_objectPrototype);
+ visitIfNeeded(visitor, &thisObject->m_functionPrototype);
+ visitIfNeeded(visitor, &thisObject->m_arrayPrototype);
+ visitIfNeeded(visitor, &thisObject->m_booleanPrototype);
+ visitIfNeeded(visitor, &thisObject->m_stringPrototype);
+ visitIfNeeded(visitor, &thisObject->m_numberPrototype);
+ visitIfNeeded(visitor, &thisObject->m_datePrototype);
+ visitIfNeeded(visitor, &thisObject->m_regExpPrototype);
+
+ visitIfNeeded(visitor, &thisObject->m_argumentsStructure);
+ visitIfNeeded(visitor, &thisObject->m_arrayStructure);
+ visitIfNeeded(visitor, &thisObject->m_booleanObjectStructure);
+ visitIfNeeded(visitor, &thisObject->m_callbackConstructorStructure);
+ visitIfNeeded(visitor, &thisObject->m_callbackFunctionStructure);
+ visitIfNeeded(visitor, &thisObject->m_callbackObjectStructure);
+ visitIfNeeded(visitor, &thisObject->m_dateStructure);
+ visitIfNeeded(visitor, &thisObject->m_emptyObjectStructure);
+ visitIfNeeded(visitor, &thisObject->m_nullPrototypeObjectStructure);
+ visitIfNeeded(visitor, &thisObject->m_errorStructure);
+ visitIfNeeded(visitor, &thisObject->m_functionStructure);
+ visitIfNeeded(visitor, &thisObject->m_boundFunctionStructure);
+ visitIfNeeded(visitor, &thisObject->m_namedFunctionStructure);
+ visitIfNeeded(visitor, &thisObject->m_numberObjectStructure);
+ visitIfNeeded(visitor, &thisObject->m_regExpMatchesArrayStructure);
+ visitIfNeeded(visitor, &thisObject->m_regExpStructure);
+ visitIfNeeded(visitor, &thisObject->m_stringObjectStructure);
+ visitIfNeeded(visitor, &thisObject->m_internalFunctionStructure);
+
+ if (thisObject->m_registerArray) {
+ // Outside the execution of global code, when our variables are torn off,
+ // we can mark the torn-off array.
+ visitor.appendValues(thisObject->m_registerArray.get(), thisObject->m_registerArraySize);
+ } else if (thisObject->m_registers) {
+ // During execution of global code, when our variables are in the register file,
+ // the symbol table tells us how many variables there are, and registers
+ // points to where they end, and the registers used for execution begin.
+ visitor.appendValues(thisObject->m_registers - thisObject->symbolTable().size(), thisObject->symbolTable().size());
+ }
+}
+
+ExecState* JSGlobalObject::globalExec()
+{
+ return CallFrame::create(m_globalCallFrame + RegisterFile::CallFrameHeaderSize);
+}
+
+void JSGlobalObject::resizeRegisters(size_t newSize)
+{
+ // Previous duplicate symbols may have created spare capacity in m_registerArray.
+ if (newSize <= m_registerArraySize)
+ return;
+
+ size_t oldSize = m_registerArraySize;
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[newSize]);
+ for (size_t i = 0; i < oldSize; ++i)
+ registerArray[i].set(globalData(), this, m_registerArray[i].get());
+ for (size_t i = oldSize; i < newSize; ++i)
+ registerArray[i].setUndefined();
+
+ WriteBarrier<Unknown>* registers = registerArray.get();
+ setRegisters(registers, registerArray.release(), newSize);
+}
+
+void JSGlobalObject::addStaticGlobals(GlobalPropertyInfo* globals, int count)
+{
+ resizeRegisters(symbolTable().size() + count);
+
+ for (int i = 0; i < count; ++i) {
+ GlobalPropertyInfo& global = globals[i];
+ ASSERT(global.attributes & DontDelete);
+
+ int index = symbolTable().size();
+ SymbolTableEntry newEntry(index, global.attributes);
+ symbolTable().add(global.identifier.impl(), newEntry);
+ registerAt(index).set(globalData(), this, global.value);
+ }
+}
+
+bool JSGlobalObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(cell);
+ if (getStaticFunctionSlot<JSVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, slot))
+ return true;
+ return thisObject->symbolTableGet(propertyName, slot);
+}
+
+bool JSGlobalObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ JSGlobalObject* thisObject = jsCast<JSGlobalObject*>(object);
+ if (getStaticFunctionDescriptor<JSVariableObject>(exec, ExecState::globalObjectTable(exec), thisObject, propertyName, descriptor))
+ return true;
+ return thisObject->symbolTableGet(propertyName, descriptor);
+}
+
+void JSGlobalObject::clearRareData(JSCell* cell)
+{
+ jsCast<JSGlobalObject*>(cell)->m_rareData.clear();
+}
+
+DynamicGlobalObjectScope::DynamicGlobalObjectScope(JSGlobalData& globalData, JSGlobalObject* dynamicGlobalObject)
+ : m_dynamicGlobalObjectSlot(globalData.dynamicGlobalObject)
+ , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot)
+{
+ if (!m_dynamicGlobalObjectSlot) {
+#if ENABLE(ASSEMBLER)
+ if (ExecutableAllocator::underMemoryPressure())
+ globalData.recompileAllJSFunctions();
+#endif
+
+ m_dynamicGlobalObjectSlot = dynamicGlobalObject;
+
+ // Reset the date cache between JS invocations to force the VM
+ // to observe time zone changes.
+ globalData.resetDateCache();
+ }
+}
+
+void slowValidateCell(JSGlobalObject* globalObject)
+{
+ if (!globalObject->isGlobalObject())
+ CRASH();
+ ASSERT_GC_OBJECT_INHERITS(globalObject, &JSGlobalObject::s_info);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObject.h b/Source/JavaScriptCore/runtime/JSGlobalObject.h
new file mode 100644
index 000000000..1caa8b187
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalObject.h
@@ -0,0 +1,510 @@
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef JSGlobalObject_h
+#define JSGlobalObject_h
+
+#include "JSArray.h"
+#include "JSGlobalData.h"
+#include "JSGlobalThis.h"
+#include "JSVariableObject.h"
+#include "JSWeakObjectMapRefInternal.h"
+#include "NumberPrototype.h"
+#include "StringPrototype.h"
+#include "StructureChain.h"
+#include <wtf/HashSet.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RandomNumber.h>
+
+namespace JSC {
+
+ class ArrayPrototype;
+ class BooleanPrototype;
+ class DatePrototype;
+ class Debugger;
+ class ErrorConstructor;
+ class FunctionPrototype;
+ class GetterSetter;
+ class GlobalCodeBlock;
+ class NativeErrorConstructor;
+ class ProgramCodeBlock;
+ class RegExpConstructor;
+ class RegExpPrototype;
+ class RegisterFile;
+
+ struct ActivationStackNode;
+ struct HashTable;
+
+ typedef Vector<ExecState*, 16> ExecStateStack;
+
+ struct GlobalObjectMethodTable {
+ typedef bool (*SupportsProfilingFunctionPtr)(const JSGlobalObject*);
+ SupportsProfilingFunctionPtr supportsProfiling;
+
+ typedef bool (*SupportsRichSourceInfoFunctionPtr)(const JSGlobalObject*);
+ SupportsRichSourceInfoFunctionPtr supportsRichSourceInfo;
+
+ typedef bool (*ShouldInterruptScriptFunctionPtr)(const JSGlobalObject*);
+ ShouldInterruptScriptFunctionPtr shouldInterruptScript;
+ };
+
+ class JSGlobalObject : public JSVariableObject {
+ private:
+ typedef HashSet<RefPtr<OpaqueJSWeakObjectMap> > WeakMapSet;
+
+ struct JSGlobalObjectRareData {
+ JSGlobalObjectRareData()
+ : profileGroup(0)
+ {
+ }
+
+ WeakMapSet weakMaps;
+ unsigned profileGroup;
+ };
+
+ protected:
+
+ RefPtr<JSGlobalData> m_globalData;
+
+ size_t m_registerArraySize;
+ Register m_globalCallFrame[RegisterFile::CallFrameHeaderSize];
+
+ WriteBarrier<ScopeChainNode> m_globalScopeChain;
+ WriteBarrier<JSObject> m_methodCallDummy;
+
+ WriteBarrier<RegExpConstructor> m_regExpConstructor;
+ WriteBarrier<ErrorConstructor> m_errorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_evalErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_rangeErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_referenceErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_syntaxErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_typeErrorConstructor;
+ WriteBarrier<NativeErrorConstructor> m_URIErrorConstructor;
+
+ WriteBarrier<JSFunction> m_evalFunction;
+ WriteBarrier<JSFunction> m_callFunction;
+ WriteBarrier<JSFunction> m_applyFunction;
+ WriteBarrier<GetterSetter> m_throwTypeErrorGetterSetter;
+
+ WriteBarrier<ObjectPrototype> m_objectPrototype;
+ WriteBarrier<FunctionPrototype> m_functionPrototype;
+ WriteBarrier<ArrayPrototype> m_arrayPrototype;
+ WriteBarrier<BooleanPrototype> m_booleanPrototype;
+ WriteBarrier<StringPrototype> m_stringPrototype;
+ WriteBarrier<NumberPrototype> m_numberPrototype;
+ WriteBarrier<DatePrototype> m_datePrototype;
+ WriteBarrier<RegExpPrototype> m_regExpPrototype;
+
+ WriteBarrier<Structure> m_argumentsStructure;
+ WriteBarrier<Structure> m_arrayStructure;
+ WriteBarrier<Structure> m_booleanObjectStructure;
+ WriteBarrier<Structure> m_callbackConstructorStructure;
+ WriteBarrier<Structure> m_callbackFunctionStructure;
+ WriteBarrier<Structure> m_callbackObjectStructure;
+ WriteBarrier<Structure> m_dateStructure;
+ WriteBarrier<Structure> m_emptyObjectStructure;
+ WriteBarrier<Structure> m_nullPrototypeObjectStructure;
+ WriteBarrier<Structure> m_errorStructure;
+ WriteBarrier<Structure> m_functionStructure;
+ WriteBarrier<Structure> m_boundFunctionStructure;
+ WriteBarrier<Structure> m_namedFunctionStructure;
+ size_t m_functionNameOffset;
+ WriteBarrier<Structure> m_numberObjectStructure;
+ WriteBarrier<Structure> m_regExpMatchesArrayStructure;
+ WriteBarrier<Structure> m_regExpStructure;
+ WriteBarrier<Structure> m_stringObjectStructure;
+ WriteBarrier<Structure> m_internalFunctionStructure;
+
+ Debugger* m_debugger;
+
+ OwnPtr<JSGlobalObjectRareData> m_rareData;
+
+ WeakRandom m_weakRandom;
+
+ SymbolTable m_symbolTable;
+
+ bool m_evalEnabled;
+
+ static JS_EXPORTDATA const GlobalObjectMethodTable s_globalObjectMethodTable;
+ const GlobalObjectMethodTable* m_globalObjectMethodTable;
+
+ void createRareDataIfNeeded()
+ {
+ if (m_rareData)
+ return;
+ m_rareData = adoptPtr(new JSGlobalObjectRareData);
+ Heap::heap(this)->addFinalizer(this, clearRareData);
+ }
+
+ public:
+ typedef JSVariableObject Base;
+
+ static JSGlobalObject* create(JSGlobalData& globalData, Structure* structure)
+ {
+ JSGlobalObject* globalObject = new (NotNull, allocateCell<JSGlobalObject>(globalData.heap)) JSGlobalObject(globalData, structure);
+ globalObject->finishCreation(globalData);
+ return globalObject;
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ protected:
+ explicit JSGlobalObject(JSGlobalData& globalData, Structure* structure, const GlobalObjectMethodTable* globalObjectMethodTable = 0)
+ : JSVariableObject(globalData, structure, &m_symbolTable, 0)
+ , m_registerArraySize(0)
+ , m_globalScopeChain()
+ , m_weakRandom(static_cast<unsigned>(randomNumber() * (std::numeric_limits<unsigned>::max() + 1.0)))
+ , m_evalEnabled(true)
+ , m_globalObjectMethodTable(globalObjectMethodTable ? globalObjectMethodTable : &s_globalObjectMethodTable)
+ {
+ }
+
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData);
+ structure()->setGlobalObject(globalData, this);
+ init(this);
+ }
+
+ void finishCreation(JSGlobalData& globalData, JSGlobalThis* thisValue)
+ {
+ Base::finishCreation(globalData);
+ structure()->setGlobalObject(globalData, this);
+ init(thisValue);
+ }
+
+ public:
+ ~JSGlobalObject();
+ static void destroy(JSCell*);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ bool hasOwnPropertyForWrite(ExecState*, const Identifier&);
+ static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&);
+
+ static void putWithAttributes(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes);
+
+ static void defineGetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes);
+ static void defineSetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes);
+
+ // We use this in the code generator as we perform symbol table
+ // lookups prior to initializing the properties
+ bool symbolTableHasProperty(const Identifier& propertyName);
+
+ // The following accessors return pristine values, even if a script
+ // replaces the global object's associated property.
+
+ RegExpConstructor* regExpConstructor() const { return m_regExpConstructor.get(); }
+
+ ErrorConstructor* errorConstructor() const { return m_errorConstructor.get(); }
+ NativeErrorConstructor* evalErrorConstructor() const { return m_evalErrorConstructor.get(); }
+ NativeErrorConstructor* rangeErrorConstructor() const { return m_rangeErrorConstructor.get(); }
+ NativeErrorConstructor* referenceErrorConstructor() const { return m_referenceErrorConstructor.get(); }
+ NativeErrorConstructor* syntaxErrorConstructor() const { return m_syntaxErrorConstructor.get(); }
+ NativeErrorConstructor* typeErrorConstructor() const { return m_typeErrorConstructor.get(); }
+ NativeErrorConstructor* URIErrorConstructor() const { return m_URIErrorConstructor.get(); }
+
+ JSFunction* evalFunction() const { return m_evalFunction.get(); }
+ JSFunction* callFunction() const { return m_callFunction.get(); }
+ JSFunction* applyFunction() const { return m_applyFunction.get(); }
+ GetterSetter* throwTypeErrorGetterSetter(ExecState* exec)
+ {
+ if (!m_throwTypeErrorGetterSetter)
+ createThrowTypeError(exec);
+ return m_throwTypeErrorGetterSetter.get();
+ }
+
+ ObjectPrototype* objectPrototype() const { return m_objectPrototype.get(); }
+ FunctionPrototype* functionPrototype() const { return m_functionPrototype.get(); }
+ ArrayPrototype* arrayPrototype() const { return m_arrayPrototype.get(); }
+ BooleanPrototype* booleanPrototype() const { return m_booleanPrototype.get(); }
+ StringPrototype* stringPrototype() const { return m_stringPrototype.get(); }
+ NumberPrototype* numberPrototype() const { return m_numberPrototype.get(); }
+ DatePrototype* datePrototype() const { return m_datePrototype.get(); }
+ RegExpPrototype* regExpPrototype() const { return m_regExpPrototype.get(); }
+
+ JSObject* methodCallDummy() const { return m_methodCallDummy.get(); }
+
+ Structure* argumentsStructure() const { return m_argumentsStructure.get(); }
+ Structure* arrayStructure() const { return m_arrayStructure.get(); }
+ Structure* booleanObjectStructure() const { return m_booleanObjectStructure.get(); }
+ Structure* callbackConstructorStructure() const { return m_callbackConstructorStructure.get(); }
+ Structure* callbackFunctionStructure() const { return m_callbackFunctionStructure.get(); }
+ Structure* callbackObjectStructure() const { return m_callbackObjectStructure.get(); }
+ Structure* dateStructure() const { return m_dateStructure.get(); }
+ Structure* emptyObjectStructure() const { return m_emptyObjectStructure.get(); }
+ Structure* nullPrototypeObjectStructure() const { return m_nullPrototypeObjectStructure.get(); }
+ Structure* errorStructure() const { return m_errorStructure.get(); }
+ Structure* functionStructure() const { return m_functionStructure.get(); }
+ Structure* boundFunctionStructure() const { return m_boundFunctionStructure.get(); }
+ Structure* namedFunctionStructure() const { return m_namedFunctionStructure.get(); }
+ size_t functionNameOffset() const { return m_functionNameOffset; }
+ Structure* numberObjectStructure() const { return m_numberObjectStructure.get(); }
+ Structure* internalFunctionStructure() const { return m_internalFunctionStructure.get(); }
+ Structure* regExpMatchesArrayStructure() const { return m_regExpMatchesArrayStructure.get(); }
+ Structure* regExpStructure() const { return m_regExpStructure.get(); }
+ Structure* stringObjectStructure() const { return m_stringObjectStructure.get(); }
+
+ void setProfileGroup(unsigned value) { createRareDataIfNeeded(); m_rareData->profileGroup = value; }
+ unsigned profileGroup() const
+ {
+ if (!m_rareData)
+ return 0;
+ return m_rareData->profileGroup;
+ }
+
+ Debugger* debugger() const { return m_debugger; }
+ void setDebugger(Debugger* debugger) { m_debugger = debugger; }
+
+ const GlobalObjectMethodTable* globalObjectMethodTable() const { return m_globalObjectMethodTable; }
+
+ static bool supportsProfiling(const JSGlobalObject*) { return false; }
+ static bool supportsRichSourceInfo(const JSGlobalObject*) { return true; }
+
+ ScopeChainNode* globalScopeChain() { return m_globalScopeChain.get(); }
+
+ ExecState* globalExec();
+
+ static bool shouldInterruptScript(const JSGlobalObject*) { return true; }
+
+ bool isDynamicScope(bool& requiresDynamicChecks) const;
+
+ void setEvalEnabled(bool enabled) { m_evalEnabled = enabled; }
+ bool evalEnabled() { return m_evalEnabled; }
+
+ void resizeRegisters(size_t newSize);
+
+ void resetPrototype(JSGlobalData&, JSValue prototype);
+
+ JSGlobalData& globalData() const { return *m_globalData.get(); }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, 0, prototype, TypeInfo(GlobalObjectType, StructureFlags), &s_info);
+ }
+
+ void registerWeakMap(OpaqueJSWeakObjectMap* map)
+ {
+ createRareDataIfNeeded();
+ m_rareData->weakMaps.add(map);
+ }
+
+ void unregisterWeakMap(OpaqueJSWeakObjectMap* map)
+ {
+ if (m_rareData)
+ m_rareData->weakMaps.remove(map);
+ }
+
+ double weakRandomNumber() { return m_weakRandom.get(); }
+ protected:
+
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
+
+ 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 createThrowTypeError(ExecState*);
+
+ void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count);
+ static void clearRareData(JSCell*);
+ };
+
+ JSGlobalObject* asGlobalObject(JSValue);
+
+ inline JSGlobalObject* asGlobalObject(JSValue value)
+ {
+ ASSERT(asObject(value)->isGlobalObject());
+ return static_cast<JSGlobalObject*>(asObject(value));
+ }
+
+ inline void JSGlobalObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray, size_t count)
+ {
+ JSVariableObject::setRegisters(registers, registerArray);
+ m_registerArraySize = count;
+ }
+
+ inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName)
+ {
+ PropertySlot slot;
+ if (JSVariableObject::getOwnPropertySlot(this, exec, propertyName, slot))
+ return true;
+ bool slotIsWriteable;
+ return symbolTableGet(propertyName, slot, slotIsWriteable);
+ }
+
+ inline bool JSGlobalObject::symbolTableHasProperty(const Identifier& propertyName)
+ {
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ return !entry.isNull();
+ }
+
+ inline JSValue Structure::prototypeForLookup(ExecState* exec) const
+ {
+ if (isObject())
+ return m_prototype.get();
+
+ ASSERT(typeInfo().type() == StringType);
+ return exec->lexicalGlobalObject()->stringPrototype();
+ }
+
+ inline StructureChain* Structure::prototypeChain(ExecState* exec) const
+ {
+ // We cache our prototype chain so our clients can share it.
+ if (!isValid(exec, m_cachedPrototypeChain.get())) {
+ JSValue prototype = prototypeForLookup(exec);
+ m_cachedPrototypeChain.set(exec->globalData(), this, StructureChain::create(exec->globalData(), prototype.isNull() ? 0 : asObject(prototype)->structure()));
+ }
+ return m_cachedPrototypeChain.get();
+ }
+
+ inline bool Structure::isValid(ExecState* exec, StructureChain* cachedPrototypeChain) const
+ {
+ if (!cachedPrototypeChain)
+ return false;
+
+ JSValue prototype = prototypeForLookup(exec);
+ WriteBarrier<Structure>* cachedStructure = cachedPrototypeChain->head();
+ while(*cachedStructure && !prototype.isNull()) {
+ if (asObject(prototype)->structure() != cachedStructure->get())
+ return false;
+ ++cachedStructure;
+ prototype = asObject(prototype)->prototype();
+ }
+ return prototype.isNull() && !*cachedStructure;
+ }
+
+ inline 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;
+ }
+
+ inline JSObject* constructEmptyObject(ExecState* exec, JSGlobalObject* globalObject)
+ {
+ return constructEmptyObject(exec, globalObject->emptyObjectStructure());
+ }
+
+ inline JSObject* constructEmptyObject(ExecState* exec)
+ {
+ return constructEmptyObject(exec, exec->lexicalGlobalObject());
+ }
+
+ inline JSArray* constructEmptyArray(ExecState* exec, JSGlobalObject* globalObject, unsigned initialLength = 0)
+ {
+ return JSArray::create(exec->globalData(), globalObject->arrayStructure(), initialLength);
+ }
+
+ inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength = 0)
+ {
+ return constructEmptyArray(exec, exec->lexicalGlobalObject(), initialLength);
+ }
+
+ inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const ArgList& values)
+ {
+ JSGlobalData& globalData = exec->globalData();
+ unsigned length = values.size();
+ JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length);
+
+ // FIXME: we should probably throw an out of memory error here, but
+ // when making this change we should check that all clients of this
+ // function will correctly handle an exception being thrown from here.
+ if (!array)
+ CRASH();
+
+ for (unsigned i = 0; i < length; ++i)
+ array->initializeIndex(globalData, i, values.at(i));
+ array->completeInitialization(length);
+ return array;
+ }
+
+ inline JSArray* constructArray(ExecState* exec, const ArgList& values)
+ {
+ return constructArray(exec, exec->lexicalGlobalObject(), values);
+ }
+
+ inline JSArray* constructArray(ExecState* exec, JSGlobalObject* globalObject, const JSValue* values, unsigned length)
+ {
+ JSGlobalData& globalData = exec->globalData();
+ JSArray* array = JSArray::tryCreateUninitialized(globalData, globalObject->arrayStructure(), length);
+
+ // FIXME: we should probably throw an out of memory error here, but
+ // when making this change we should check that all clients of this
+ // function will correctly handle an exception being thrown from here.
+ if (!array)
+ CRASH();
+
+ for (unsigned i = 0; i < length; ++i)
+ array->initializeIndex(globalData, i, values[i]);
+ array->completeInitialization(length);
+ return array;
+ }
+
+ inline JSArray* constructArray(ExecState* exec, const JSValue* values, unsigned length)
+ {
+ return constructArray(exec, exec->lexicalGlobalObject(), values, length);
+ }
+
+ class DynamicGlobalObjectScope {
+ WTF_MAKE_NONCOPYABLE(DynamicGlobalObjectScope);
+ public:
+ DynamicGlobalObjectScope(JSGlobalData&, JSGlobalObject*);
+
+ ~DynamicGlobalObjectScope()
+ {
+ m_dynamicGlobalObjectSlot = m_savedDynamicGlobalObject;
+ }
+
+ private:
+ JSGlobalObject*& m_dynamicGlobalObjectSlot;
+ JSGlobalObject* m_savedDynamicGlobalObject;
+ };
+
+ inline bool JSGlobalObject::isDynamicScope(bool&) const
+ {
+ return true;
+ }
+
+} // namespace JSC
+
+#endif // JSGlobalObject_h
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
new file mode 100644
index 000000000..bf6b31ef1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp
@@ -0,0 +1,718 @@
+/*
+ * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2007 Maks Orlovich
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "JSGlobalObjectFunctions.h"
+
+#include "CallFrame.h"
+#include "Interpreter.h"
+#include "JSGlobalObject.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+#include "Lexer.h"
+#include "LiteralParser.h"
+#include "Nodes.h"
+#include "Parser.h"
+#include "UStringBuilder.h"
+#include "dtoa.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StringExtras.h>
+#include <wtf/unicode/UTF8.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace JSC {
+
+static JSValue encode(ExecState* exec, const char* doNotEscape)
+{
+ UString str = exec->argument(0).toString(exec);
+ CString cstr = str.utf8(true);
+ if (!cstr.data())
+ return throwError(exec, createURIError(exec, "String contained an illegal UTF-16 sequence."));
+
+ JSStringBuilder builder;
+ const char* p = cstr.data();
+ for (size_t k = 0; k < cstr.length(); k++, p++) {
+ char c = *p;
+ if (c && strchr(doNotEscape, c))
+ builder.append(c);
+ else {
+ char tmp[4];
+ snprintf(tmp, sizeof(tmp), "%%%02X", static_cast<unsigned char>(c));
+ builder.append(tmp);
+ }
+ }
+ return builder.build(exec);
+}
+
+template <typename CharType>
+ALWAYS_INLINE
+static JSValue decode(ExecState* exec, const CharType* characters, int length, const char* doNotUnescape, bool strict)
+{
+ JSStringBuilder builder;
+ int k = 0;
+ UChar u = 0;
+ while (k < length) {
+ const CharType* p = characters + k;
+ CharType c = *p;
+ if (c == '%') {
+ int charLen = 0;
+ if (k <= length - 3 && isASCIIHexDigit(p[1]) && isASCIIHexDigit(p[2])) {
+ const char b0 = Lexer<CharType>::convertHex(p[1], p[2]);
+ const int sequenceLen = UTF8SequenceLength(b0);
+ if (sequenceLen && k <= length - sequenceLen * 3) {
+ charLen = sequenceLen * 3;
+ char sequence[5];
+ sequence[0] = b0;
+ for (int i = 1; i < sequenceLen; ++i) {
+ const CharType* q = p + i * 3;
+ if (q[0] == '%' && isASCIIHexDigit(q[1]) && isASCIIHexDigit(q[2]))
+ sequence[i] = Lexer<CharType>::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.
+ builder.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, createURIError(exec, "URI error"));
+ // 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 <= length - 6 && p[1] == 'u'
+ && isASCIIHexDigit(p[2]) && isASCIIHexDigit(p[3])
+ && isASCIIHexDigit(p[4]) && isASCIIHexDigit(p[5])) {
+ charLen = 6;
+ u = Lexer<UChar>::convertUnicode(p[2], p[3], p[4], p[5]);
+ }
+ }
+ if (charLen && (u == 0 || u >= 128 || !strchr(doNotUnescape, u))) {
+ if (u < 256)
+ builder.append(static_cast<LChar>(u));
+ else
+ builder.append(u);
+ k += charLen;
+ continue;
+ }
+ }
+ k++;
+ builder.append(c);
+ }
+ return builder.build(exec);
+}
+
+static JSValue decode(ExecState* exec, const char* doNotUnescape, bool strict)
+{
+ JSStringBuilder builder;
+ UString str = exec->argument(0).toString(exec);
+
+ if (str.is8Bit())
+ return decode(exec, str.characters8(), str.length(), doNotUnescape, strict);
+ return decode(exec, str.characters16(), str.length(), doNotUnescape, strict);
+}
+
+bool isStrWhiteSpace(UChar c)
+{
+ switch (c) {
+ // ECMA-262-5th 7.2 & 7.3
+ case 0x0009:
+ case 0x000A:
+ case 0x000B:
+ case 0x000C:
+ case 0x000D:
+ case 0x0020:
+ case 0x00A0:
+ case 0x2028:
+ case 0x2029:
+ case 0xFEFF:
+ 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 LChar* s, int length, int radix)
+{
+ double number = 0.0;
+ double radixMultiplier = 1.0;
+
+ for (const LChar* p = s + length - 1; p >= s; p--) {
+ if (radixMultiplier == std::numeric_limits<double>::infinity()) {
+ if (*p != '0') {
+ number = std::numeric_limits<double>::infinity();
+ break;
+ }
+ } else {
+ int digit = parseDigit(*p, radix);
+ number += digit * radixMultiplier;
+ }
+
+ radixMultiplier *= radix;
+ }
+
+ return number;
+}
+
+double parseIntOverflow(const UChar* s, int length, int radix)
+{
+ double number = 0.0;
+ double radixMultiplier = 1.0;
+
+ for (const UChar* p = s + length - 1; p >= s; p--) {
+ if (radixMultiplier == std::numeric_limits<double>::infinity()) {
+ if (*p != '0') {
+ number = std::numeric_limits<double>::infinity();
+ break;
+ }
+ } else {
+ int digit = parseDigit(*p, radix);
+ number += digit * radixMultiplier;
+ }
+
+ radixMultiplier *= radix;
+ }
+
+ return number;
+}
+
+// ES5.1 15.1.2.2
+template <typename CharType>
+ALWAYS_INLINE
+static double parseInt(const UString& s, const CharType* data, int radix)
+{
+ // 1. Let inputString be ToString(string).
+ // 2. Let S be a newly created substring of inputString consisting of the first character that is not a
+ // StrWhiteSpaceChar and all characters following that character. (In other words, remove leading white
+ // space.) If inputString does not contain any such characters, let S be the empty string.
+ int length = s.length();
+ int p = 0;
+ while (p < length && isStrWhiteSpace(data[p]))
+ ++p;
+
+ // 3. Let sign be 1.
+ // 4. If S is not empty and the first character of S is a minus sign -, let sign be -1.
+ // 5. If S is not empty and the first character of S is a plus sign + or a minus sign -, then remove the first character from S.
+ double sign = 1;
+ if (p < length) {
+ if (data[p] == '+')
+ ++p;
+ else if (data[p] == '-') {
+ sign = -1;
+ ++p;
+ }
+ }
+
+ // 6. Let R = ToInt32(radix).
+ // 7. Let stripPrefix be true.
+ // 8. If R != 0,then
+ // b. If R != 16, let stripPrefix be false.
+ // 9. Else, R == 0
+ // a. LetR = 10.
+ // 10. If stripPrefix is true, then
+ // a. If the length of S is at least 2 and the first two characters of S are either ―0x or ―0X,
+ // then remove the first two characters from S and let R = 16.
+ // 11. If S contains any character that is not a radix-R digit, then let Z be the substring of S
+ // consisting of all characters before the first such character; otherwise, let Z be S.
+ 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)
+ radix = 10;
+
+ // 8.a If R < 2 or R > 36, then return NaN.
+ if (radix < 2 || radix > 36)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // 13. Let mathInt be the mathematical integer value that is represented by Z in radix-R notation, using the letters
+ // A-Z and a-z for digits with values 10 through 35. (However, if R is 10 and Z contains more than 20 significant
+ // digits, every significant digit after the 20th may be replaced by a 0 digit, at the option of the implementation;
+ // and if R is not 2, 4, 8, 10, 16, or 32, then mathInt may be an implementation-dependent approximation to the
+ // mathematical integer value that is represented by Z in radix-R notation.)
+ // 14. Let number be the Number value for mathInt.
+ int firstDigitPosition = p;
+ bool sawDigit = false;
+ double number = 0;
+ while (p < length) {
+ int digit = parseDigit(data[p], radix);
+ if (digit == -1)
+ break;
+ sawDigit = true;
+ number *= radix;
+ number += digit;
+ ++p;
+ }
+ if (number >= mantissaOverflowLowerBound) {
+ if (radix == 10)
+ number = WTF::strtod(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), 0);
+ else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
+ number = parseIntOverflow(s.substringSharingImpl(firstDigitPosition, p - firstDigitPosition).utf8().data(), p - firstDigitPosition, radix);
+ }
+
+ // 12. If Z is empty, return NaN.
+ if (!sawDigit)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ // 15. Return sign x number.
+ return sign * number;
+}
+
+static double parseInt(const UString& s, int radix)
+{
+ if (s.is8Bit())
+ return parseInt(s, s.characters8(), radix);
+ return parseInt(s, s.characters16(), radix);
+}
+
+static const int SizeOfInfinity = 8;
+
+template <typename CharType>
+static bool isInfinity(const CharType* data, const CharType* end)
+{
+ return (end - data) >= SizeOfInfinity
+ && data[0] == 'I'
+ && data[1] == 'n'
+ && data[2] == 'f'
+ && data[3] == 'i'
+ && data[4] == 'n'
+ && data[5] == 'i'
+ && data[6] == 't'
+ && data[7] == 'y';
+}
+
+// See ecma-262 9.3.1
+template <typename CharType>
+static double jsHexIntegerLiteral(const CharType*& data, const CharType* end)
+{
+ // Hex number.
+ data += 2;
+ const CharType* firstDigitPosition = data;
+ double number = 0;
+ while (true) {
+ number = number * 16 + toASCIIHexValue(*data);
+ ++data;
+ if (data == end)
+ break;
+ if (!isASCIIHexDigit(*data))
+ break;
+ }
+ if (number >= mantissaOverflowLowerBound)
+ number = parseIntOverflow(firstDigitPosition, data - firstDigitPosition, 16);
+
+ return number;
+}
+
+// See ecma-262 9.3.1
+template <typename CharType>
+static double jsStrDecimalLiteral(const CharType*& data, const CharType* end)
+{
+ ASSERT(data < end);
+
+ // Copy the sting into a null-terminated byte buffer, and call strtod.
+ Vector<char, 32> byteBuffer;
+ for (const CharType* characters = data; characters < end; ++characters) {
+ CharType character = *characters;
+ byteBuffer.append(isASCII(character) ? static_cast<char>(character) : 0);
+ }
+ byteBuffer.append(0);
+ char* endOfNumber;
+ double number = WTF::strtod(byteBuffer.data(), &endOfNumber);
+
+ // Check if strtod found a number; if so return it.
+ ptrdiff_t consumed = endOfNumber - byteBuffer.data();
+ if (consumed) {
+ data += consumed;
+ return number;
+ }
+
+ // Check for [+-]?Infinity
+ switch (*data) {
+ case 'I':
+ if (isInfinity(data, end)) {
+ data += SizeOfInfinity;
+ return std::numeric_limits<double>::infinity();
+ }
+ break;
+
+ case '+':
+ if (isInfinity(data + 1, end)) {
+ data += SizeOfInfinity + 1;
+ return std::numeric_limits<double>::infinity();
+ }
+ break;
+
+ case '-':
+ if (isInfinity(data + 1, end)) {
+ data += SizeOfInfinity + 1;
+ return -std::numeric_limits<double>::infinity();
+ }
+ break;
+ }
+
+ // Not a number.
+ return std::numeric_limits<double>::quiet_NaN();
+}
+
+template <typename CharType>
+static double toDouble(const CharType* characters, unsigned size)
+{
+ const CharType* endCharacters = characters + size;
+
+ // Skip leading white space.
+ for (; characters < endCharacters; ++characters) {
+ if (!isStrWhiteSpace(*characters))
+ break;
+ }
+
+ // Empty string.
+ if (characters == endCharacters)
+ return 0.0;
+
+ double number;
+ if (characters[0] == '0' && characters + 2 < endCharacters && (characters[1] | 0x20) == 'x' && isASCIIHexDigit(characters[2]))
+ number = jsHexIntegerLiteral(characters, endCharacters);
+ else
+ number = jsStrDecimalLiteral(characters, endCharacters);
+
+ // Allow trailing white space.
+ for (; characters < endCharacters; ++characters) {
+ if (!isStrWhiteSpace(*characters))
+ break;
+ }
+ if (characters != endCharacters)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ return number;
+}
+
+// See ecma-262 9.3.1
+double jsToNumber(const UString& s)
+{
+ unsigned size = s.length();
+
+ if (size == 1) {
+ UChar c = s[0];
+ if (isASCIIDigit(c))
+ return c - '0';
+ if (isStrWhiteSpace(c))
+ return 0;
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ if (s.is8Bit())
+ return toDouble(s.characters8(), size);
+ return toDouble(s.characters16(), size);
+}
+
+static double parseFloat(const UString& s)
+{
+ unsigned size = s.length();
+
+ if (size == 1) {
+ UChar c = s[0];
+ if (isASCIIDigit(c))
+ return c - '0';
+ return std::numeric_limits<double>::quiet_NaN();
+ }
+
+ if (s.is8Bit()) {
+ const LChar* data = s.characters8();
+ const LChar* end = data + size;
+
+ // Skip leading white space.
+ for (; data < end; ++data) {
+ if (!isStrWhiteSpace(*data))
+ break;
+ }
+
+ // Empty string.
+ if (data == end)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ return jsStrDecimalLiteral(data, end);
+ }
+
+ const UChar* data = s.characters16();
+ const UChar* end = data + size;
+
+ // Skip leading white space.
+ for (; data < end; ++data) {
+ if (!isStrWhiteSpace(*data))
+ break;
+ }
+
+ // Empty string.
+ if (data == end)
+ return std::numeric_limits<double>::quiet_NaN();
+
+ return jsStrDecimalLiteral(data, end);
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState* exec)
+{
+ JSObject* thisObject = exec->hostThisValue().toThisObject(exec);
+ JSObject* unwrappedObject = thisObject->unwrappedObject();
+ if (!unwrappedObject->isGlobalObject() || static_cast<JSGlobalObject*>(unwrappedObject)->evalFunction() != exec->callee())
+ return throwVMError(exec, createEvalError(exec, "The \"this\" value passed to eval must be the global object from which eval originated"));
+
+ JSValue x = exec->argument(0);
+ if (!x.isString())
+ return JSValue::encode(x);
+
+ UString s = x.toString(exec);
+
+ if (s.is8Bit()) {
+ LiteralParser<LChar> preparser(exec, s.characters8(), s.length(), NonStrictJSON);
+ if (JSValue parsedObject = preparser.tryLiteralParse())
+ return JSValue::encode(parsedObject);
+ } else {
+ LiteralParser<UChar> preparser(exec, s.characters16(), s.length(), NonStrictJSON);
+ if (JSValue parsedObject = preparser.tryLiteralParse())
+ return JSValue::encode(parsedObject);
+ }
+
+ EvalExecutable* eval = EvalExecutable::create(exec, makeSource(s), false);
+ JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain());
+ if (error)
+ return throwVMError(exec, error);
+
+ return JSValue::encode(exec->interpreter()->execute(eval, exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain()));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec)
+{
+ JSValue value = exec->argument(0);
+ JSValue radixValue = exec->argument(1);
+
+ // Optimized handling for numbers:
+ // If the argument is 0 or a number in range 10^-6 <= n < INT_MAX+1, then parseInt
+ // results in a truncation to integer. In the case of -0, this is converted to 0.
+ //
+ // This is also a truncation for values in the range INT_MAX+1 <= n < 10^21,
+ // however these values cannot be trivially truncated to int since 10^21 exceeds
+ // even the int64_t range. Negative numbers are a little trickier, the case for
+ // values in the range -10^21 < n <= -1 are similar to those for integer, but
+ // values in the range -1 < n <= -10^-6 need to truncate to -0, not 0.
+ static const double tenToTheMinus6 = 0.000001;
+ static const double intMaxPlusOne = 2147483648.0;
+ if (value.isNumber()) {
+ double n = value.asNumber();
+ if (((n < intMaxPlusOne && n >= tenToTheMinus6) || !n) && radixValue.isUndefinedOrNull())
+ return JSValue::encode(jsNumber(static_cast<int32_t>(n)));
+ }
+
+ // If ToString throws, we shouldn't call ToInt32.
+ UString s = value.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(jsNumber(parseInt(s, radixValue.toInt32(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState* exec)
+{
+ return JSValue::encode(jsNumber(parseFloat(exec->argument(0).toString(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState* exec)
+{
+ return JSValue::encode(jsBoolean(isnan(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState* exec)
+{
+ double n = exec->argument(0).toNumber(exec);
+ return JSValue::encode(jsBoolean(isfinite(n)));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState* exec)
+{
+ static const char do_not_unescape_when_decoding_URI[] =
+ "#$&+,/:;=?@";
+
+ return JSValue::encode(decode(exec, do_not_unescape_when_decoding_URI, true));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState* exec)
+{
+ return JSValue::encode(decode(exec, "", true));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState* exec)
+{
+ static const char do_not_escape_when_encoding_URI[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "!#$&'()*+,-./:;=?@_~";
+
+ return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState* exec)
+{
+ static const char do_not_escape_when_encoding_URI_component[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "!'()*-._~";
+
+ return JSValue::encode(encode(exec, do_not_escape_when_encoding_URI_component));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState* exec)
+{
+ static const char do_not_escape[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "*+-./@_";
+
+ JSStringBuilder builder;
+ UString str = exec->argument(0).toString(exec);
+ if (str.is8Bit()) {
+ const LChar* c = str.characters8();
+ for (unsigned k = 0; k < str.length(); k++, c++) {
+ int u = c[0];
+ if (u && strchr(do_not_escape, static_cast<char>(u)))
+ builder.append(c, 1);
+ else {
+ char tmp[4];
+ snprintf(tmp, sizeof(tmp), "%%%02X", u);
+ builder.append(tmp);
+ }
+ }
+
+ return JSValue::encode(builder.build(exec));
+ }
+
+ const UChar* c = str.characters16();
+ for (unsigned k = 0; k < str.length(); k++, c++) {
+ int u = c[0];
+ if (u > 255) {
+ char tmp[7];
+ snprintf(tmp, sizeof(tmp), "%%u%04X", u);
+ builder.append(tmp);
+ } else if (u != 0 && strchr(do_not_escape, static_cast<char>(u)))
+ builder.append(c, 1);
+ else {
+ char tmp[4];
+ snprintf(tmp, sizeof(tmp), "%%%02X", u);
+ builder.append(tmp);
+ }
+ }
+
+ return JSValue::encode(builder.build(exec));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState* exec)
+{
+ UStringBuilder builder;
+ UString str = exec->argument(0).toString(exec);
+ int k = 0;
+ int len = str.length();
+
+ if (str.is8Bit()) {
+ const LChar* characters = str.characters8();
+ LChar convertedLChar;
+ while (k < len) {
+ const LChar* c = characters + k;
+ if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
+ if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
+ builder.append(Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]));
+ k += 6;
+ continue;
+ }
+ } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
+ convertedLChar = LChar(Lexer<LChar>::convertHex(c[1], c[2]));
+ c = &convertedLChar;
+ k += 2;
+ }
+ builder.append(*c);
+ k++;
+ }
+ } else {
+ const UChar* characters = str.characters16();
+
+ while (k < len) {
+ const UChar* c = characters + k;
+ UChar convertedUChar;
+ if (c[0] == '%' && k <= len - 6 && c[1] == 'u') {
+ if (isASCIIHexDigit(c[2]) && isASCIIHexDigit(c[3]) && isASCIIHexDigit(c[4]) && isASCIIHexDigit(c[5])) {
+ convertedUChar = Lexer<UChar>::convertUnicode(c[2], c[3], c[4], c[5]);
+ c = &convertedUChar;
+ k += 5;
+ }
+ } else if (c[0] == '%' && k <= len - 3 && isASCIIHexDigit(c[1]) && isASCIIHexDigit(c[2])) {
+ convertedUChar = UChar(Lexer<UChar>::convertHex(c[1], c[2]));
+ c = &convertedUChar;
+ k += 2;
+ }
+ k++;
+ builder.append(*c);
+ }
+ }
+
+ return JSValue::encode(jsString(exec, builder.toUString()));
+}
+
+EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState* exec)
+{
+ return throwVMTypeError(exec);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h
new file mode 100644
index 000000000..1183dfac5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalObjectFunctions.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009, 2010 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 "JSValue.h"
+#include <wtf/unicode/Unicode.h>
+
+namespace JSC {
+
+ class ArgList;
+ class ExecState;
+ class JSObject;
+
+ // FIXME: These functions should really be in JSGlobalObject.cpp, but putting them there
+ // is a 0.5% reduction.
+
+ EncodedJSValue JSC_HOST_CALL globalFuncEval(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncParseInt(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncParseFloat(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncIsNaN(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncIsFinite(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncDecodeURI(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncDecodeURIComponent(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncEncodeURI(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncEncodeURIComponent(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncEscape(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncUnescape(ExecState*);
+ EncodedJSValue JSC_HOST_CALL globalFuncThrowTypeError(ExecState*);
+
+ static const double mantissaOverflowLowerBound = 9007199254740992.0;
+ double parseIntOverflow(const LChar*, int length, int radix);
+ ALWAYS_INLINE double parseIntOverflow(const char* s, int length, int radix) { return parseIntOverflow(reinterpret_cast<const LChar*>(s), length, radix); }
+ double parseIntOverflow(const UChar*, int length, int radix);
+ bool isStrWhiteSpace(UChar);
+ double jsToNumber(const UString& s);
+
+} // namespace JSC
+
+#endif // JSGlobalObjectFunctions_h
diff --git a/Source/JavaScriptCore/runtime/JSGlobalThis.cpp b/Source/JavaScriptCore/runtime/JSGlobalThis.cpp
new file mode 100644
index 000000000..8b2a7a1ef
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalThis.cpp
@@ -0,0 +1,56 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSGlobalThis.h"
+
+#include "JSGlobalObject.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(JSGlobalThis);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSGlobalThis);
+
+const ClassInfo JSGlobalThis::s_info = { "JSGlobalThis", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSGlobalThis) };
+
+void JSGlobalThis::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSGlobalThis* thisObject = jsCast<JSGlobalThis*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+
+ Base::visitChildren(thisObject, visitor);
+ if (thisObject->m_unwrappedObject)
+ visitor.append(&thisObject->m_unwrappedObject);
+}
+
+JSGlobalObject* JSGlobalThis::unwrappedObject()
+{
+ return m_unwrappedObject.get();
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSGlobalThis.h b/Source/JavaScriptCore/runtime/JSGlobalThis.h
new file mode 100644
index 000000000..fa5de0491
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSGlobalThis.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSGlobalThis_h
+#define JSGlobalThis_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class JSGlobalThis : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ static JSGlobalThis* create(JSGlobalData& globalData, Structure* structure)
+ {
+ JSGlobalThis* globalThis = new (NotNull, allocateCell<JSGlobalThis>(globalData.heap)) JSGlobalThis(globalData, structure);
+ globalThis->finishCreation(globalData);
+ return globalThis;
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSValue prototype)
+ {
+ return Structure::create(globalData, 0, prototype, TypeInfo(GlobalThisType, StructureFlags), &s_info);
+ }
+
+ static JS_EXPORTDATA const JSC::ClassInfo s_info;
+
+ JSGlobalObject* unwrappedObject();
+
+protected:
+ JSGlobalThis(JSGlobalData& globalData, Structure* structure)
+ : JSNonFinalObject(globalData, structure)
+ {
+ }
+
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData);
+ }
+
+ static const unsigned StructureFlags = OverridesVisitChildren | Base::StructureFlags;
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ WriteBarrier<JSGlobalObject> m_unwrappedObject;
+};
+
+} // namespace JSC
+
+#endif // JSGlobalThis_h
diff --git a/Source/JavaScriptCore/runtime/JSLock.cpp b/Source/JavaScriptCore/runtime/JSLock.cpp
new file mode 100644
index 000000000..90e2f5d2a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSLock.cpp
@@ -0,0 +1,263 @@
+/*
+ * 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 "Heap.h"
+#include "CallFrame.h"
+#include "JSObject.h"
+#include "ScopeChain.h"
+
+#if USE(PTHREADS)
+#include <pthread.h>
+#endif
+
+namespace JSC {
+
+// JSLock is only needed to support an obsolete execution model where JavaScriptCore
+// automatically protected against concurrent access from multiple threads.
+// So it's safe to disable it on non-mac platforms where we don't have native pthreads.
+#if (OS(DARWIN) || USE(PTHREADS))
+
+// Acquire this mutex before accessing lock-related data.
+static pthread_mutex_t JSMutex = PTHREAD_MUTEX_INITIALIZER;
+
+// Thread-specific key that tells whether a thread holds the JSMutex, and how many times it was taken recursively.
+pthread_key_t JSLockCount;
+
+static void createJSLockCount()
+{
+ pthread_key_create(&JSLockCount, 0);
+}
+
+pthread_once_t createJSLockCountOnce = PTHREAD_ONCE_INIT;
+
+// Lock nesting count.
+intptr_t JSLock::lockCount()
+{
+ pthread_once(&createJSLockCountOnce, createJSLockCount);
+
+ return reinterpret_cast<intptr_t>(pthread_getspecific(JSLockCount));
+}
+
+static void setLockCount(intptr_t count)
+{
+ ASSERT(count >= 0);
+ pthread_setspecific(JSLockCount, reinterpret_cast<void*>(count));
+}
+
+JSLock::JSLock(ExecState* exec)
+ : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly)
+{
+ lock(m_lockBehavior);
+}
+
+JSLock::JSLock(JSGlobalData* globalData)
+ : m_lockBehavior(globalData->isSharedInstance() ? LockForReal : SilenceAssertionsOnly)
+{
+ lock(m_lockBehavior);
+}
+
+void JSLock::lock(JSLockBehavior lockBehavior)
+{
+#ifdef NDEBUG
+ // Locking "not for real" is a debug-only feature.
+ if (lockBehavior == SilenceAssertionsOnly)
+ return;
+#endif
+
+ pthread_once(&createJSLockCountOnce, createJSLockCount);
+
+ intptr_t currentLockCount = lockCount();
+ if (!currentLockCount && lockBehavior == LockForReal) {
+ int result = pthread_mutex_lock(&JSMutex);
+ ASSERT_UNUSED(result, !result);
+ }
+ setLockCount(currentLockCount + 1);
+}
+
+void JSLock::unlock(JSLockBehavior lockBehavior)
+{
+ ASSERT(lockCount());
+
+#ifdef NDEBUG
+ // Locking "not for real" is a debug-only feature.
+ if (lockBehavior == SilenceAssertionsOnly)
+ return;
+#endif
+
+ intptr_t newLockCount = lockCount() - 1;
+ setLockCount(newLockCount);
+ if (!newLockCount && lockBehavior == LockForReal) {
+ int result = pthread_mutex_unlock(&JSMutex);
+ ASSERT_UNUSED(result, !result);
+ }
+}
+
+void JSLock::lock(ExecState* exec)
+{
+ lock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly);
+}
+
+void JSLock::unlock(ExecState* exec)
+{
+ unlock(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly);
+}
+
+bool JSLock::currentThreadIsHoldingLock()
+{
+ pthread_once(&createJSLockCountOnce, createJSLockCount);
+ return !!pthread_getspecific(JSLockCount);
+}
+
+// This is fairly nasty. We allow multiple threads to run on the same
+// context, and we do not require any locking semantics in doing so -
+// clients of the API may simply use the context from multiple threads
+// concurently, and assume this will work. In order to make this work,
+// We lock the context when a thread enters, and unlock it when it leaves.
+// However we do not only unlock when the thread returns from its
+// entry point (evaluate script or call function), we also unlock the
+// context if the thread leaves JSC by making a call out to an external
+// function through a callback.
+//
+// All threads using the context share the same JS stack (the RegisterFile).
+// Whenever a thread calls into JSC it starts using the RegisterFile from the
+// previous 'high water mark' - the maximum point the stack has ever grown to
+// (returned by RegisterFile::end()). So if a first thread calls out to a
+// callback, and a second thread enters JSC, then also exits by calling out
+// to a callback, we can be left with stackframes from both threads in the
+// RegisterFile. As such, a problem may occur should the first thread's
+// callback complete first, and attempt to return to JSC. Were we to allow
+// this to happen, and were its stack to grow further, then it may potentially
+// write over the second thread's call frames.
+//
+// In avoid JS stack corruption we enforce a policy of only ever allowing two
+// threads to use a JS context concurrently, and only allowing the second of
+// these threads to execute until it has completed and fully returned from its
+// outermost call into JSC. We enforce this policy using 'lockDropDepth'. The
+// first time a thread exits it will call DropAllLocks - which will do as expected
+// and drop locks allowing another thread to enter. Should another thread, or the
+// same thread again, enter JSC (through evaluate script or call function), and exit
+// again through a callback, then the locks will not be dropped when DropAllLocks
+// is called (since lockDropDepth is non-zero). Since this thread is still holding
+// the locks, only it will re able to re-enter JSC (either be returning from the
+// callback, or by re-entering through another call to evaulate script or call
+// function).
+//
+// This policy is slightly more restricive than it needs to be for correctness -
+// we could validly allow futher entries into JSC from other threads, we only
+// need ensure that callbacks return in the reverse chronological order of the
+// order in which they were made - though implementing the less restrictive policy
+// would likely increase complexity and overhead.
+//
+static unsigned lockDropDepth = 0;
+
+JSLock::DropAllLocks::DropAllLocks(ExecState* exec)
+ : m_lockBehavior(exec->globalData().isSharedInstance() ? LockForReal : SilenceAssertionsOnly)
+{
+ pthread_once(&createJSLockCountOnce, createJSLockCount);
+
+ if (lockDropDepth++) {
+ m_lockCount = 0;
+ return;
+ }
+
+ m_lockCount = JSLock::lockCount();
+ for (intptr_t i = 0; i < m_lockCount; i++)
+ JSLock::unlock(m_lockBehavior);
+}
+
+JSLock::DropAllLocks::DropAllLocks(JSLockBehavior JSLockBehavior)
+ : m_lockBehavior(JSLockBehavior)
+{
+ pthread_once(&createJSLockCountOnce, createJSLockCount);
+
+ if (lockDropDepth++) {
+ m_lockCount = 0;
+ return;
+ }
+
+ // It is necessary to drop even "unreal" locks, because having a non-zero lock count
+ // will prevent a real lock from being taken.
+
+ m_lockCount = JSLock::lockCount();
+ for (intptr_t i = 0; i < m_lockCount; i++)
+ JSLock::unlock(m_lockBehavior);
+}
+
+JSLock::DropAllLocks::~DropAllLocks()
+{
+ for (intptr_t i = 0; i < m_lockCount; i++)
+ JSLock::lock(m_lockBehavior);
+
+ --lockDropDepth;
+}
+
+#else // (OS(DARWIN) || USE(PTHREADS))
+
+JSLock::JSLock(ExecState*)
+ : m_lockBehavior(SilenceAssertionsOnly)
+{
+}
+
+// If threading support is off, set the lock count to a constant value of 1 so ssertions
+// that the lock is held don't fail
+intptr_t JSLock::lockCount()
+{
+ return 1;
+}
+
+bool JSLock::currentThreadIsHoldingLock()
+{
+ return true;
+}
+
+void JSLock::lock(JSLockBehavior)
+{
+}
+
+void JSLock::unlock(JSLockBehavior)
+{
+}
+
+void JSLock::lock(ExecState*)
+{
+}
+
+void JSLock::unlock(ExecState*)
+{
+}
+
+JSLock::DropAllLocks::DropAllLocks(ExecState*)
+{
+}
+
+JSLock::DropAllLocks::DropAllLocks(JSLockBehavior)
+{
+}
+
+JSLock::DropAllLocks::~DropAllLocks()
+{
+}
+
+#endif // (OS(DARWIN) || USE(PTHREADS))
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSLock.h b/Source/JavaScriptCore/runtime/JSLock.h
new file mode 100644
index 000000000..7b07b4fb3
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSLock.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (C) 2005, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef JSLock_h
+#define JSLock_h
+
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+
+namespace JSC {
+
+ // To make it safe to use JavaScript on multiple threads, it is
+ // important to lock before doing anything that allocates a
+ // JavaScript data structure or that interacts with shared state
+ // such as the protect count hash table. The simplest way to lock
+ // is to create a local JSLock object in the scope where the lock
+ // must be held. The lock is recursive so nesting is ok. The JSLock
+ // object also acts as a convenience short-hand for running important
+ // initialization routines.
+
+ // To avoid deadlock, sometimes it is necessary to temporarily
+ // release the lock. Since it is recursive you actually have to
+ // release all locks held by your thread. This is safe to do if
+ // you are executing code that doesn't require the lock, and you
+ // reacquire the right number of locks at the end. You can do this
+ // by constructing a locally scoped JSLock::DropAllLocks object. The
+ // DropAllLocks object takes care to release the JSLock only if your
+ // thread acquired it to begin with.
+
+ // For contexts other than the single shared one, implicit locking is not done,
+ // but we still need to perform all the counting in order to keep debug
+ // assertions working, so that clients that use the shared context don't break.
+
+ class ExecState;
+ class JSGlobalData;
+
+ enum JSLockBehavior { SilenceAssertionsOnly, LockForReal };
+
+ class JSLock {
+ WTF_MAKE_NONCOPYABLE(JSLock);
+ public:
+ JSLock(ExecState*);
+ JSLock(JSGlobalData*);
+
+ JSLock(JSLockBehavior lockBehavior)
+ : m_lockBehavior(lockBehavior)
+ {
+#ifdef NDEBUG
+ // Locking "not for real" is a debug-only feature.
+ if (lockBehavior == SilenceAssertionsOnly)
+ return;
+#endif
+ lock(lockBehavior);
+ }
+
+ ~JSLock()
+ {
+#ifdef NDEBUG
+ // Locking "not for real" is a debug-only feature.
+ if (m_lockBehavior == SilenceAssertionsOnly)
+ return;
+#endif
+ unlock(m_lockBehavior);
+ }
+
+ static void lock(JSLockBehavior);
+ static void unlock(JSLockBehavior);
+ static void lock(ExecState*);
+ static void unlock(ExecState*);
+
+ static intptr_t lockCount();
+ static bool currentThreadIsHoldingLock();
+
+ JSLockBehavior m_lockBehavior;
+
+ class DropAllLocks {
+ WTF_MAKE_NONCOPYABLE(DropAllLocks);
+ public:
+ DropAllLocks(ExecState* exec);
+ DropAllLocks(JSLockBehavior);
+ ~DropAllLocks();
+
+ private:
+ intptr_t m_lockCount;
+ JSLockBehavior m_lockBehavior;
+ };
+ };
+
+} // namespace
+
+#endif // JSLock_h
diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.cpp b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp
new file mode 100644
index 000000000..682400292
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSNotAnObject.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "config.h"
+#include "JSNotAnObject.h"
+
+#include <wtf/UnusedParam.h>
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(JSNotAnObject);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSNotAnObject);
+
+const ClassInfo JSNotAnObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSNotAnObject) };
+
+// JSValue methods
+JSValue JSNotAnObject::defaultValue(const JSObject*, ExecState* exec, PreferredPrimitiveType)
+{
+ ASSERT_UNUSED(exec, exec->hadException());
+ return jsNumber(0);
+}
+
+// JSObject methods
+bool JSNotAnObject::getOwnPropertySlot(JSCell*, ExecState* exec, const Identifier&, PropertySlot&)
+{
+ ASSERT_UNUSED(exec, exec->hadException());
+ return false;
+}
+
+bool JSNotAnObject::getOwnPropertySlotByIndex(JSCell*, ExecState* exec, unsigned, PropertySlot&)
+{
+ ASSERT_UNUSED(exec, exec->hadException());
+ return false;
+}
+
+bool JSNotAnObject::getOwnPropertyDescriptor(JSObject*, ExecState* exec, const Identifier&, PropertyDescriptor&)
+{
+ ASSERT_UNUSED(exec, exec->hadException());
+ return false;
+}
+
+void JSNotAnObject::put(JSCell*, ExecState* exec, const Identifier& , JSValue, PutPropertySlot&)
+{
+ ASSERT_UNUSED(exec, exec->hadException());
+}
+
+void JSNotAnObject::putByIndex(JSCell*, ExecState* exec, unsigned, JSValue)
+{
+ ASSERT_UNUSED(exec, exec->hadException());
+}
+
+bool JSNotAnObject::deleteProperty(JSCell*, ExecState* exec, const Identifier&)
+{
+ ASSERT_UNUSED(exec, exec->hadException());
+ return false;
+}
+
+bool JSNotAnObject::deletePropertyByIndex(JSCell*, ExecState* exec, unsigned)
+{
+ ASSERT_UNUSED(exec, exec->hadException());
+ return false;
+}
+
+void JSNotAnObject::getOwnPropertyNames(JSObject*, ExecState* exec, PropertyNameArray&, EnumerationMode)
+{
+ ASSERT_UNUSED(exec, exec->hadException());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSNotAnObject.h b/Source/JavaScriptCore/runtime/JSNotAnObject.h
new file mode 100644
index 000000000..51ba456e1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSNotAnObject.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSNotAnObject_h
+#define JSNotAnObject_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+ // This unholy class is used to allow us to avoid multiple exception checks
+ // in certain SquirrelFish bytecodes -- effectively it just silently consumes
+ // any operations performed on the result of a failed toObject call.
+ class JSNotAnObject : public JSNonFinalObject {
+ private:
+ JSNotAnObject(ExecState* exec)
+ : JSNonFinalObject(exec->globalData(), exec->globalData().notAnObjectStructure.get())
+ {
+ }
+
+ public:
+ typedef JSNonFinalObject Base;
+
+ static JSNotAnObject* create(ExecState* exec)
+ {
+ JSNotAnObject* object = new (NotNull, allocateCell<JSNotAnObject>(*exec->heap())) JSNotAnObject(exec);
+ object->finishCreation(exec->globalData());
+ return object;
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+ private:
+
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags;
+
+ // JSValue methods
+ static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
+
+ // JSObject methods
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+ static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue);
+
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
+ static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
+
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ };
+
+} // namespace JSC
+
+#endif // JSNotAnObject_h
diff --git a/Source/JavaScriptCore/runtime/JSONObject.cpp b/Source/JavaScriptCore/runtime/JSONObject.cpp
new file mode 100644
index 000000000..05c6c2953
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSONObject.cpp
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSONObject.h"
+
+#include "BooleanObject.h"
+#include "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSArray.h"
+#include "JSGlobalObject.h"
+#include "LiteralParser.h"
+#include "Local.h"
+#include "LocalScope.h"
+#include "Lookup.h"
+#include "PropertyNameArray.h"
+#include "UStringBuilder.h"
+#include "UStringConcatenate.h"
+#include <wtf/MathExtras.h>
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(JSONObject);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSONObject);
+
+static EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState*);
+static EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState*);
+
+}
+
+#include "JSONObject.lut.h"
+
+namespace JSC {
+
+JSONObject::JSONObject(JSGlobalObject* globalObject, Structure* structure)
+ : JSNonFinalObject(globalObject->globalData(), structure)
+{
+}
+
+void JSONObject::finishCreation(JSGlobalObject* globalObject)
+{
+ Base::finishCreation(globalObject->globalData());
+ ASSERT(inherits(&s_info));
+}
+
+// PropertyNameForFunctionCall objects must be on the stack, since the JSValue that they create is not marked.
+class PropertyNameForFunctionCall {
+public:
+ PropertyNameForFunctionCall(const Identifier&);
+ PropertyNameForFunctionCall(unsigned);
+
+ JSValue value(ExecState*) const;
+
+private:
+ const Identifier* m_identifier;
+ unsigned m_number;
+ mutable JSValue m_value;
+};
+
+class Stringifier {
+ WTF_MAKE_NONCOPYABLE(Stringifier);
+public:
+ Stringifier(ExecState*, const Local<Unknown>& replacer, const Local<Unknown>& space);
+ Local<Unknown> stringify(Handle<Unknown>);
+
+ void visitAggregate(SlotVisitor&);
+
+private:
+ class Holder {
+ public:
+ Holder(JSGlobalData&, JSObject*);
+
+ JSObject* object() const { return m_object.get(); }
+
+ bool appendNextProperty(Stringifier&, UStringBuilder&);
+
+ private:
+ Local<JSObject> m_object;
+ const bool m_isArray;
+ bool m_isJSArray;
+ unsigned m_index;
+ unsigned m_size;
+ RefPtr<PropertyNameArrayData> m_propertyNames;
+ };
+
+ friend class Holder;
+
+ static void appendQuotedString(UStringBuilder&, const UString&);
+
+ JSValue toJSON(JSValue, const PropertyNameForFunctionCall&);
+
+ enum StringifyResult { StringifyFailed, StringifySucceeded, StringifyFailedDueToUndefinedValue };
+ StringifyResult appendStringifiedValue(UStringBuilder&, JSValue, JSObject* holder, const PropertyNameForFunctionCall&);
+
+ bool willIndent() const;
+ void indent();
+ void unindent();
+ void startNewLine(UStringBuilder&) const;
+
+ ExecState* const m_exec;
+ const Local<Unknown> m_replacer;
+ bool m_usingArrayReplacer;
+ PropertyNameArray m_arrayReplacerPropertyNames;
+ CallType m_replacerCallType;
+ CallData m_replacerCallData;
+ const UString m_gap;
+
+ Vector<Holder, 16> m_holderStack;
+ UString m_repeatedGap;
+ UString m_indent;
+};
+
+// ------------------------------ helper functions --------------------------------
+
+static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value)
+{
+ if (!value.isObject())
+ return value;
+ JSObject* object = asObject(value);
+ if (object->inherits(&NumberObject::s_info))
+ return jsNumber(object->toNumber(exec));
+ if (object->inherits(&StringObject::s_info))
+ return jsString(exec, object->toString(exec));
+ if (object->inherits(&BooleanObject::s_info))
+ return object->toPrimitive(exec);
+ return value;
+}
+
+static inline UString gap(ExecState* exec, JSValue space)
+{
+ const unsigned maxGapLength = 10;
+ space = unwrapBoxedPrimitive(exec, space);
+
+ // If the space value is a number, create a gap string with that number of spaces.
+ if (space.isNumber()) {
+ double spaceCount = space.asNumber();
+ int count;
+ if (spaceCount > maxGapLength)
+ count = maxGapLength;
+ else if (!(spaceCount > 0))
+ count = 0;
+ else
+ count = static_cast<int>(spaceCount);
+ UChar spaces[maxGapLength];
+ for (int i = 0; i < count; ++i)
+ spaces[i] = ' ';
+ return UString(spaces, count);
+ }
+
+ // If the space value is a string, use it as the gap string, otherwise use no gap string.
+ UString spaces = space.getString(exec);
+ if (spaces.length() > maxGapLength) {
+ spaces = spaces.substringSharingImpl(0, maxGapLength);
+ }
+ return spaces;
+}
+
+// ------------------------------ PropertyNameForFunctionCall --------------------------------
+
+inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(const Identifier& identifier)
+ : m_identifier(&identifier)
+{
+}
+
+inline PropertyNameForFunctionCall::PropertyNameForFunctionCall(unsigned number)
+ : m_identifier(0)
+ , m_number(number)
+{
+}
+
+JSValue PropertyNameForFunctionCall::value(ExecState* exec) const
+{
+ if (!m_value) {
+ if (m_identifier)
+ m_value = jsString(exec, m_identifier->ustring());
+ else
+ m_value = jsNumber(m_number);
+ }
+ return m_value;
+}
+
+// ------------------------------ Stringifier --------------------------------
+
+Stringifier::Stringifier(ExecState* exec, const Local<Unknown>& replacer, const Local<Unknown>& space)
+ : m_exec(exec)
+ , m_replacer(replacer)
+ , m_usingArrayReplacer(false)
+ , m_arrayReplacerPropertyNames(exec)
+ , m_replacerCallType(CallTypeNone)
+ , m_gap(gap(exec, space.get()))
+{
+ if (!m_replacer.isObject())
+ return;
+
+ if (m_replacer.asObject()->inherits(&JSArray::s_info)) {
+ m_usingArrayReplacer = true;
+ Handle<JSObject> array = m_replacer.asObject();
+ unsigned length = array->get(exec, exec->globalData().propertyNames->length).toUInt32(exec);
+ for (unsigned i = 0; i < length; ++i) {
+ JSValue name = array->get(exec, i);
+ if (exec->hadException())
+ break;
+
+ UString propertyName;
+ if (name.getString(exec, propertyName)) {
+ m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName));
+ continue;
+ }
+
+ if (name.isNumber()) {
+ m_arrayReplacerPropertyNames.add(Identifier::from(exec, name.asNumber()));
+ continue;
+ }
+
+ if (name.isObject()) {
+ if (!asObject(name)->inherits(&NumberObject::s_info) && !asObject(name)->inherits(&StringObject::s_info))
+ continue;
+ propertyName = name.toString(exec);
+ if (exec->hadException())
+ break;
+ m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName));
+ }
+ }
+ return;
+ }
+
+ m_replacerCallType = m_replacer.asObject()->methodTable()->getCallData(m_replacer.asObject().get(), m_replacerCallData);
+}
+
+Local<Unknown> Stringifier::stringify(Handle<Unknown> value)
+{
+ JSObject* object = constructEmptyObject(m_exec);
+ if (m_exec->hadException())
+ return Local<Unknown>(m_exec->globalData(), jsNull());
+
+ PropertyNameForFunctionCall emptyPropertyName(m_exec->globalData().propertyNames->emptyIdentifier);
+ object->putDirect(m_exec->globalData(), m_exec->globalData().propertyNames->emptyIdentifier, value.get());
+
+ UStringBuilder result;
+ if (appendStringifiedValue(result, value.get(), object, emptyPropertyName) != StringifySucceeded)
+ return Local<Unknown>(m_exec->globalData(), jsUndefined());
+ if (m_exec->hadException())
+ return Local<Unknown>(m_exec->globalData(), jsNull());
+
+ return Local<Unknown>(m_exec->globalData(), jsString(m_exec, result.toUString()));
+}
+
+template <typename CharType>
+static void appendStringToUStringBuilder(UStringBuilder& builder, const CharType* data, int length)
+{
+ for (int i = 0; i < length; ++i) {
+ int start = i;
+ while (i < length && (data[i] > 0x1F && data[i] != '"' && data[i] != '\\'))
+ ++i;
+ builder.append(data + start, i - start);
+ if (i >= length)
+ break;
+ switch (data[i]) {
+ case '\t':
+ builder.append('\\');
+ builder.append('t');
+ break;
+ case '\r':
+ builder.append('\\');
+ builder.append('r');
+ break;
+ case '\n':
+ builder.append('\\');
+ builder.append('n');
+ break;
+ case '\f':
+ builder.append('\\');
+ builder.append('f');
+ break;
+ case '\b':
+ builder.append('\\');
+ builder.append('b');
+ break;
+ case '"':
+ builder.append('\\');
+ builder.append('"');
+ break;
+ case '\\':
+ builder.append('\\');
+ builder.append('\\');
+ break;
+ default:
+ static const char hexDigits[] = "0123456789abcdef";
+ UChar ch = data[i];
+ LChar hex[] = { '\\', 'u', hexDigits[(ch >> 12) & 0xF], hexDigits[(ch >> 8) & 0xF], hexDigits[(ch >> 4) & 0xF], hexDigits[ch & 0xF] };
+ builder.append(hex, WTF_ARRAY_LENGTH(hex));
+ break;
+ }
+ }
+}
+
+void Stringifier::appendQuotedString(UStringBuilder& builder, const UString& value)
+{
+ int length = value.length();
+
+ builder.append('"');
+
+ if (value.is8Bit())
+ appendStringToUStringBuilder<LChar>(builder, value.characters8(), length);
+ else
+ appendStringToUStringBuilder<UChar>(builder, value.characters16(), length);
+
+ builder.append('"');
+}
+
+inline JSValue Stringifier::toJSON(JSValue value, const PropertyNameForFunctionCall& propertyName)
+{
+ ASSERT(!m_exec->hadException());
+ if (!value.isObject() || !asObject(value)->hasProperty(m_exec, m_exec->globalData().propertyNames->toJSON))
+ return value;
+
+ JSValue toJSONFunction = asObject(value)->get(m_exec, m_exec->globalData().propertyNames->toJSON);
+ if (m_exec->hadException())
+ return jsNull();
+
+ if (!toJSONFunction.isObject())
+ return value;
+
+ JSObject* object = asObject(toJSONFunction);
+ CallData callData;
+ CallType callType = object->methodTable()->getCallData(object, callData);
+ if (callType == CallTypeNone)
+ return value;
+
+ MarkedArgumentBuffer args;
+ args.append(propertyName.value(m_exec));
+ return call(m_exec, object, callType, callData, value, args);
+}
+
+Stringifier::StringifyResult Stringifier::appendStringifiedValue(UStringBuilder& builder, JSValue value, JSObject* holder, const PropertyNameForFunctionCall& propertyName)
+{
+ // Call the toJSON function.
+ value = toJSON(value, propertyName);
+ if (m_exec->hadException())
+ return StringifyFailed;
+
+ // Call the replacer function.
+ if (m_replacerCallType != CallTypeNone) {
+ MarkedArgumentBuffer args;
+ args.append(propertyName.value(m_exec));
+ args.append(value);
+ value = call(m_exec, m_replacer.get(), m_replacerCallType, m_replacerCallData, holder, args);
+ if (m_exec->hadException())
+ return StringifyFailed;
+ }
+
+ if (value.isUndefined() && !holder->inherits(&JSArray::s_info))
+ return StringifyFailedDueToUndefinedValue;
+
+ if (value.isNull()) {
+ builder.append("null");
+ return StringifySucceeded;
+ }
+
+ value = unwrapBoxedPrimitive(m_exec, value);
+
+ if (m_exec->hadException())
+ return StringifyFailed;
+
+ if (value.isBoolean()) {
+ builder.append(value.isTrue() ? "true" : "false");
+ return StringifySucceeded;
+ }
+
+ UString stringValue;
+ if (value.getString(m_exec, stringValue)) {
+ appendQuotedString(builder, stringValue);
+ return StringifySucceeded;
+ }
+
+ if (value.isNumber()) {
+ double number = value.asNumber();
+ if (!isfinite(number))
+ builder.append("null");
+ else
+ builder.append(UString::number(number));
+ return StringifySucceeded;
+ }
+
+ if (!value.isObject())
+ return StringifyFailed;
+
+ JSObject* object = asObject(value);
+
+ CallData callData;
+ if (object->methodTable()->getCallData(object, callData) != CallTypeNone) {
+ if (holder->inherits(&JSArray::s_info)) {
+ builder.append("null");
+ return StringifySucceeded;
+ }
+ return StringifyFailedDueToUndefinedValue;
+ }
+
+ // Handle cycle detection, and put the holder on the stack.
+ for (unsigned i = 0; i < m_holderStack.size(); i++) {
+ if (m_holderStack[i].object() == object) {
+ throwError(m_exec, createTypeError(m_exec, "JSON.stringify cannot serialize cyclic structures."));
+ return StringifyFailed;
+ }
+ }
+ bool holderStackWasEmpty = m_holderStack.isEmpty();
+ m_holderStack.append(Holder(m_exec->globalData(), object));
+ if (!holderStackWasEmpty)
+ return StringifySucceeded;
+
+ // If this is the outermost call, then loop to handle everything on the holder stack.
+ TimeoutChecker localTimeoutChecker(m_exec->globalData().timeoutChecker);
+ localTimeoutChecker.reset();
+ unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck();
+ do {
+ while (m_holderStack.last().appendNextProperty(*this, builder)) {
+ if (m_exec->hadException())
+ return StringifyFailed;
+ if (!--tickCount) {
+ if (localTimeoutChecker.didTimeOut(m_exec)) {
+ throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
+ return StringifyFailed;
+ }
+ tickCount = localTimeoutChecker.ticksUntilNextCheck();
+ }
+ }
+ m_holderStack.removeLast();
+ } while (!m_holderStack.isEmpty());
+ return StringifySucceeded;
+}
+
+inline bool Stringifier::willIndent() const
+{
+ return !m_gap.isEmpty();
+}
+
+inline void Stringifier::indent()
+{
+ // Use a single shared string, m_repeatedGap, so we don't keep allocating new ones as we indent and unindent.
+ unsigned newSize = m_indent.length() + m_gap.length();
+ if (newSize > m_repeatedGap.length())
+ m_repeatedGap = makeUString(m_repeatedGap, m_gap);
+ ASSERT(newSize <= m_repeatedGap.length());
+ m_indent = m_repeatedGap.substringSharingImpl(0, newSize);
+}
+
+inline void Stringifier::unindent()
+{
+ ASSERT(m_indent.length() >= m_gap.length());
+ m_indent = m_repeatedGap.substringSharingImpl(0, m_indent.length() - m_gap.length());
+}
+
+inline void Stringifier::startNewLine(UStringBuilder& builder) const
+{
+ if (m_gap.isEmpty())
+ return;
+ builder.append('\n');
+ builder.append(m_indent);
+}
+
+inline Stringifier::Holder::Holder(JSGlobalData& globalData, JSObject* object)
+ : m_object(globalData, object)
+ , m_isArray(object->inherits(&JSArray::s_info))
+ , m_index(0)
+{
+}
+
+bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, UStringBuilder& builder)
+{
+ ASSERT(m_index <= m_size);
+
+ ExecState* exec = stringifier.m_exec;
+
+ // First time through, initialize.
+ if (!m_index) {
+ if (m_isArray) {
+ m_isJSArray = isJSArray(m_object.get());
+ m_size = m_object->get(exec, exec->globalData().propertyNames->length).toUInt32(exec);
+ builder.append('[');
+ } else {
+ if (stringifier.m_usingArrayReplacer)
+ m_propertyNames = stringifier.m_arrayReplacerPropertyNames.data();
+ else {
+ PropertyNameArray objectPropertyNames(exec);
+ m_object->methodTable()->getOwnPropertyNames(m_object.get(), exec, objectPropertyNames, ExcludeDontEnumProperties);
+ m_propertyNames = objectPropertyNames.releaseData();
+ }
+ m_size = m_propertyNames->propertyNameVector().size();
+ builder.append('{');
+ }
+ stringifier.indent();
+ }
+
+ // Last time through, finish up and return false.
+ if (m_index == m_size) {
+ stringifier.unindent();
+ if (m_size && builder[builder.length() - 1] != '{')
+ stringifier.startNewLine(builder);
+ builder.append(m_isArray ? ']' : '}');
+ return false;
+ }
+
+ // Handle a single element of the array or object.
+ unsigned index = m_index++;
+ unsigned rollBackPoint = 0;
+ StringifyResult stringifyResult;
+ if (m_isArray) {
+ // Get the value.
+ JSValue value;
+ if (m_isJSArray && asArray(m_object.get())->canGetIndex(index))
+ value = asArray(m_object.get())->getIndex(index);
+ else {
+ PropertySlot slot(m_object.get());
+ if (!m_object->methodTable()->getOwnPropertySlotByIndex(m_object.get(), exec, index, slot))
+ slot.setUndefined();
+ if (exec->hadException())
+ return false;
+ value = slot.getValue(exec, index);
+ }
+
+ // Append the separator string.
+ if (index)
+ builder.append(',');
+ stringifier.startNewLine(builder);
+
+ // Append the stringified value.
+ stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), index);
+ } else {
+ // Get the value.
+ PropertySlot slot(m_object.get());
+ Identifier& propertyName = m_propertyNames->propertyNameVector()[index];
+ if (!m_object->methodTable()->getOwnPropertySlot(m_object.get(), exec, propertyName, slot))
+ return true;
+ JSValue value = slot.getValue(exec, propertyName);
+ if (exec->hadException())
+ return false;
+
+ rollBackPoint = builder.length();
+
+ // Append the separator string.
+ if (builder[rollBackPoint - 1] != '{')
+ builder.append(',');
+ stringifier.startNewLine(builder);
+
+ // Append the property name.
+ appendQuotedString(builder, propertyName.ustring());
+ builder.append(':');
+ if (stringifier.willIndent())
+ builder.append(' ');
+
+ // Append the stringified value.
+ stringifyResult = stringifier.appendStringifiedValue(builder, value, m_object.get(), propertyName);
+ }
+
+ // From this point on, no access to the this pointer or to any members, because the
+ // Holder object may have moved if the call to stringify pushed a new Holder onto
+ // m_holderStack.
+
+ switch (stringifyResult) {
+ case StringifyFailed:
+ builder.append("null");
+ break;
+ case StringifySucceeded:
+ break;
+ case StringifyFailedDueToUndefinedValue:
+ // This only occurs when get an undefined value for an object property.
+ // In this case we don't want the separator and property name that we
+ // already appended, so roll back.
+ builder.resize(rollBackPoint);
+ break;
+ }
+
+ return true;
+}
+
+// ------------------------------ JSONObject --------------------------------
+
+const ClassInfo JSONObject::s_info = { "JSON", &JSNonFinalObject::s_info, 0, ExecState::jsonTable, CREATE_METHOD_TABLE(JSONObject) };
+
+/* Source for JSONObject.lut.h
+@begin jsonTable
+ parse JSONProtoFuncParse DontEnum|Function 2
+ stringify JSONProtoFuncStringify DontEnum|Function 3
+@end
+*/
+
+// ECMA 15.8
+
+bool JSONObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<JSObject>(exec, ExecState::jsonTable(exec), jsCast<JSONObject*>(cell), propertyName, slot);
+}
+
+bool JSONObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<JSObject>(exec, ExecState::jsonTable(exec), jsCast<JSONObject*>(object), propertyName, descriptor);
+}
+
+class Walker {
+public:
+ Walker(ExecState* exec, Handle<JSObject> function, CallType callType, CallData callData)
+ : m_exec(exec)
+ , m_function(exec->globalData(), function)
+ , m_callType(callType)
+ , m_callData(callData)
+ {
+ }
+ JSValue walk(JSValue unfiltered);
+private:
+ JSValue callReviver(JSObject* thisObj, JSValue property, JSValue unfiltered)
+ {
+ MarkedArgumentBuffer args;
+ args.append(property);
+ args.append(unfiltered);
+ return call(m_exec, m_function.get(), m_callType, m_callData, thisObj, args);
+ }
+
+ friend class Holder;
+
+ ExecState* m_exec;
+ Local<JSObject> m_function;
+ CallType m_callType;
+ CallData m_callData;
+};
+
+// We clamp recursion well beyond anything reasonable, but we also have a timeout check
+// to guard against "infinite" execution by inserting arbitrarily large objects.
+static const unsigned maximumFilterRecursion = 40000;
+enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember,
+ ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember };
+NEVER_INLINE JSValue Walker::walk(JSValue unfiltered)
+{
+ Vector<PropertyNameArray, 16> propertyStack;
+ Vector<uint32_t, 16> indexStack;
+ LocalStack<JSObject, 16> objectStack(m_exec->globalData());
+ LocalStack<JSArray, 16> arrayStack(m_exec->globalData());
+
+ Vector<WalkerState, 16> stateStack;
+ WalkerState state = StateUnknown;
+ JSValue inValue = unfiltered;
+ JSValue outValue = jsNull();
+
+ TimeoutChecker localTimeoutChecker(m_exec->globalData().timeoutChecker);
+ localTimeoutChecker.reset();
+ unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck();
+ while (1) {
+ switch (state) {
+ arrayStartState:
+ case ArrayStartState: {
+ ASSERT(inValue.isObject());
+ ASSERT(isJSArray(asObject(inValue)) || asObject(inValue)->inherits(&JSArray::s_info));
+ if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
+ return throwError(m_exec, createStackOverflowError(m_exec));
+
+ JSArray* array = asArray(inValue);
+ arrayStack.push(array);
+ indexStack.append(0);
+ // fallthrough
+ }
+ arrayStartVisitMember:
+ case ArrayStartVisitMember: {
+ if (!--tickCount) {
+ if (localTimeoutChecker.didTimeOut(m_exec))
+ return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
+ tickCount = localTimeoutChecker.ticksUntilNextCheck();
+ }
+
+ JSArray* array = arrayStack.peek();
+ uint32_t index = indexStack.last();
+ if (index == array->length()) {
+ outValue = array;
+ arrayStack.pop();
+ indexStack.removeLast();
+ break;
+ }
+ if (isJSArray(array) && array->canGetIndex(index))
+ inValue = array->getIndex(index);
+ else {
+ PropertySlot slot;
+ if (array->methodTable()->getOwnPropertySlotByIndex(array, m_exec, index, slot))
+ inValue = slot.getValue(m_exec, index);
+ else
+ inValue = jsUndefined();
+ }
+
+ if (inValue.isObject()) {
+ stateStack.append(ArrayEndVisitMember);
+ goto stateUnknown;
+ } else
+ outValue = inValue;
+ // fallthrough
+ }
+ case ArrayEndVisitMember: {
+ JSArray* array = arrayStack.peek();
+ JSValue filteredValue = callReviver(array, jsString(m_exec, UString::number(indexStack.last())), outValue);
+ if (filteredValue.isUndefined())
+ array->methodTable()->deletePropertyByIndex(array, m_exec, indexStack.last());
+ else {
+ if (isJSArray(array) && array->canSetIndex(indexStack.last()))
+ array->setIndex(m_exec->globalData(), indexStack.last(), filteredValue);
+ else
+ array->methodTable()->putByIndex(array, m_exec, indexStack.last(), filteredValue);
+ }
+ if (m_exec->hadException())
+ return jsNull();
+ indexStack.last()++;
+ goto arrayStartVisitMember;
+ }
+ objectStartState:
+ case ObjectStartState: {
+ ASSERT(inValue.isObject());
+ ASSERT(!isJSArray(asObject(inValue)) && !asObject(inValue)->inherits(&JSArray::s_info));
+ if (objectStack.size() + arrayStack.size() > maximumFilterRecursion)
+ return throwError(m_exec, createStackOverflowError(m_exec));
+
+ JSObject* object = asObject(inValue);
+ objectStack.push(object);
+ indexStack.append(0);
+ propertyStack.append(PropertyNameArray(m_exec));
+ object->methodTable()->getOwnPropertyNames(object, m_exec, propertyStack.last(), ExcludeDontEnumProperties);
+ // fallthrough
+ }
+ objectStartVisitMember:
+ case ObjectStartVisitMember: {
+ if (!--tickCount) {
+ if (localTimeoutChecker.didTimeOut(m_exec))
+ return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
+ tickCount = localTimeoutChecker.ticksUntilNextCheck();
+ }
+
+ JSObject* object = objectStack.peek();
+ uint32_t index = indexStack.last();
+ PropertyNameArray& properties = propertyStack.last();
+ if (index == properties.size()) {
+ outValue = object;
+ objectStack.pop();
+ indexStack.removeLast();
+ propertyStack.removeLast();
+ break;
+ }
+ PropertySlot slot;
+ if (object->methodTable()->getOwnPropertySlot(object, m_exec, properties[index], slot))
+ inValue = slot.getValue(m_exec, properties[index]);
+ else
+ inValue = jsUndefined();
+
+ // The holder may be modified by the reviver function so any lookup may throw
+ if (m_exec->hadException())
+ return jsNull();
+
+ if (inValue.isObject()) {
+ stateStack.append(ObjectEndVisitMember);
+ goto stateUnknown;
+ } else
+ outValue = inValue;
+ // fallthrough
+ }
+ case ObjectEndVisitMember: {
+ JSObject* object = objectStack.peek();
+ Identifier prop = propertyStack.last()[indexStack.last()];
+ PutPropertySlot slot;
+ JSValue filteredValue = callReviver(object, jsString(m_exec, prop.ustring()), outValue);
+ if (filteredValue.isUndefined())
+ object->methodTable()->deleteProperty(object, m_exec, prop);
+ else
+ object->methodTable()->put(object, m_exec, prop, filteredValue, slot);
+ if (m_exec->hadException())
+ return jsNull();
+ indexStack.last()++;
+ goto objectStartVisitMember;
+ }
+ stateUnknown:
+ case StateUnknown:
+ if (!inValue.isObject()) {
+ outValue = inValue;
+ break;
+ }
+ JSObject* object = asObject(inValue);
+ if (isJSArray(object) || object->inherits(&JSArray::s_info))
+ goto arrayStartState;
+ goto objectStartState;
+ }
+ if (stateStack.isEmpty())
+ break;
+
+ state = stateStack.last();
+ stateStack.removeLast();
+
+ if (!--tickCount) {
+ if (localTimeoutChecker.didTimeOut(m_exec))
+ return throwError(m_exec, createInterruptedExecutionException(&m_exec->globalData()));
+ tickCount = localTimeoutChecker.ticksUntilNextCheck();
+ }
+ }
+ JSObject* finalHolder = constructEmptyObject(m_exec);
+ PutPropertySlot slot;
+ finalHolder->methodTable()->put(finalHolder, m_exec, m_exec->globalData().propertyNames->emptyIdentifier, outValue, slot);
+ return callReviver(finalHolder, jsEmptyString(m_exec), outValue);
+}
+
+// ECMA-262 v5 15.12.2
+EncodedJSValue JSC_HOST_CALL JSONProtoFuncParse(ExecState* exec)
+{
+ if (!exec->argumentCount())
+ return throwVMError(exec, createError(exec, "JSON.parse requires at least one parameter"));
+ JSValue value = exec->argument(0);
+ UString source = value.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+
+ JSValue unfiltered;
+ LocalScope scope(exec->globalData());
+ if (source.is8Bit()) {
+ LiteralParser<LChar> jsonParser(exec, source.characters8(), source.length(), StrictJSON);
+ unfiltered = jsonParser.tryLiteralParse();
+ if (!unfiltered)
+ return throwVMError(exec, createSyntaxError(exec, jsonParser.getErrorMessage()));
+ } else {
+ LiteralParser<UChar> jsonParser(exec, source.characters16(), source.length(), StrictJSON);
+ unfiltered = jsonParser.tryLiteralParse();
+ if (!unfiltered)
+ return throwVMError(exec, createSyntaxError(exec, jsonParser.getErrorMessage()));
+ }
+
+ if (exec->argumentCount() < 2)
+ return JSValue::encode(unfiltered);
+
+ JSValue function = exec->argument(1);
+ CallData callData;
+ CallType callType = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return JSValue::encode(unfiltered);
+ return JSValue::encode(Walker(exec, Local<JSObject>(exec->globalData(), asObject(function)), callType, callData).walk(unfiltered));
+}
+
+// ECMA-262 v5 15.12.3
+EncodedJSValue JSC_HOST_CALL JSONProtoFuncStringify(ExecState* exec)
+{
+ if (!exec->argumentCount())
+ return throwVMError(exec, createError(exec, "No input to stringify"));
+ LocalScope scope(exec->globalData());
+ Local<Unknown> value(exec->globalData(), exec->argument(0));
+ Local<Unknown> replacer(exec->globalData(), exec->argument(1));
+ Local<Unknown> space(exec->globalData(), exec->argument(2));
+ return JSValue::encode(Stringifier(exec, replacer, space).stringify(value).get());
+}
+
+UString JSONStringify(ExecState* exec, JSValue value, unsigned indent)
+{
+ LocalScope scope(exec->globalData());
+ Local<Unknown> result = Stringifier(exec, Local<Unknown>(exec->globalData(), jsNull()), Local<Unknown>(exec->globalData(), jsNumber(indent))).stringify(Local<Unknown>(exec->globalData(), value));
+ if (result.isUndefinedOrNull())
+ return UString();
+ return result.getString(exec);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSONObject.h b/Source/JavaScriptCore/runtime/JSONObject.h
new file mode 100644
index 000000000..29535f6d0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSONObject.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSONObject_h
+#define JSONObject_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+ class Stringifier;
+
+ class JSONObject : public JSNonFinalObject {
+ public:
+ typedef JSNonFinalObject Base;
+
+ static JSONObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ JSONObject* object = new (NotNull, allocateCell<JSONObject>(*exec->heap())) JSONObject(globalObject, structure);
+ object->finishCreation(globalObject);
+ return object;
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+ protected:
+ void finishCreation(JSGlobalObject*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags;
+
+ private:
+ JSONObject(JSGlobalObject*, Structure*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ };
+
+ UString JSONStringify(ExecState* exec, JSValue value, unsigned indent);
+
+} // namespace JSC
+
+#endif // JSONObject_h
diff --git a/Source/JavaScriptCore/runtime/JSObject.cpp b/Source/JavaScriptCore/runtime/JSObject.cpp
new file mode 100644
index 000000000..9cc29617a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSObject.cpp
@@ -0,0 +1,848 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2008, 2009 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 "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "JSGlobalThis.h"
+#include "Lookup.h"
+#include "NativeErrorConstructor.h"
+#include "Nodes.h"
+#include "ObjectPrototype.h"
+#include "Operations.h"
+#include "PropertyDescriptor.h"
+#include "PropertyNameArray.h"
+#include <math.h>
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(JSObject);
+ASSERT_CLASS_FITS_IN_CELL(JSNonFinalObject);
+ASSERT_CLASS_FITS_IN_CELL(JSFinalObject);
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSObject);
+
+const char* StrictModeReadonlyPropertyWriteError = "Attempted to assign to readonly property.";
+
+const ClassInfo JSObject::s_info = { "Object", 0, 0, 0, CREATE_METHOD_TABLE(JSObject) };
+
+const ClassInfo JSFinalObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSFinalObject) };
+
+void JSFinalObject::destroy(JSCell* cell)
+{
+ jsCast<JSFinalObject*>(cell)->JSFinalObject::~JSFinalObject();
+}
+
+void JSNonFinalObject::destroy(JSCell* cell)
+{
+ jsCast<JSNonFinalObject*>(cell)->JSNonFinalObject::~JSNonFinalObject();
+}
+
+static inline void getClassPropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ // Add properties from the static hashtables of properties
+ for (; classInfo; classInfo = classInfo->parentClass) {
+ const HashTable* table = classInfo->propHashTable(exec);
+ if (!table)
+ continue;
+ table->initializeIfNeeded(exec);
+ ASSERT(table->table);
+
+ int hashSizeMask = table->compactSize - 1;
+ const HashEntry* entry = table->table;
+ for (int i = 0; i <= hashSizeMask; ++i, ++entry) {
+ if (entry->key() && (!(entry->attributes() & DontEnum) || (mode == IncludeDontEnumProperties)))
+ propertyNames.add(entry->key());
+ }
+ }
+}
+
+void JSObject::finalize(JSCell* cell)
+{
+ delete [] jsCast<JSObject*>(cell)->m_propertyStorage.get();
+}
+
+void JSObject::destroy(JSCell* cell)
+{
+ jsCast<JSObject*>(cell)->JSObject::~JSObject();
+}
+
+void JSObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+#if !ASSERT_DISABLED
+ bool wasCheckingForDefaultMarkViolation = visitor.m_isCheckingForDefaultMarkViolation;
+ visitor.m_isCheckingForDefaultMarkViolation = false;
+#endif
+
+ JSCell::visitChildren(thisObject, visitor);
+
+ PropertyStorage storage = thisObject->propertyStorage();
+ size_t storageSize = thisObject->structure()->propertyStorageSize();
+ visitor.appendValues(storage, storageSize);
+ if (thisObject->m_inheritorID)
+ visitor.append(&thisObject->m_inheritorID);
+
+#if !ASSERT_DISABLED
+ visitor.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation;
+#endif
+}
+
+UString JSObject::className(const JSObject* object)
+{
+ const ClassInfo* info = object->classInfo();
+ ASSERT(info);
+ return info->className;
+}
+
+bool JSObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ return thisObject->methodTable()->getOwnPropertySlot(thisObject, exec, Identifier::from(exec, propertyName), slot);
+}
+
+static void throwSetterError(ExecState* exec)
+{
+ throwError(exec, createTypeError(exec, "setting a property that has only a getter"));
+}
+
+// ECMA 8.6.2.2
+void JSObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ ASSERT(value);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(thisObject));
+ JSGlobalData& globalData = exec->globalData();
+
+ if (propertyName == exec->propertyNames().underscoreProto) {
+ // Setting __proto__ to a non-object, non-null value is silently ignored to match Mozilla.
+ if (!value.isObject() && !value.isNull())
+ return;
+
+ if (!thisObject->isExtensible()) {
+ if (slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return;
+ }
+
+ if (!thisObject->setPrototypeWithCycleCheck(globalData, value))
+ throwError(exec, createError(exec, "cyclic __proto__ value"));
+ return;
+ }
+
+ // Check if there are any setters or getters in the prototype chain
+ JSValue prototype;
+ for (JSObject* obj = thisObject; !obj->structure()->hasGetterSetterProperties(); obj = asObject(prototype)) {
+ prototype = obj->prototype();
+ if (prototype.isNull()) {
+ if (!thisObject->putDirectInternal(globalData, propertyName, value, 0, true, slot, getJSFunction(value)) && slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return;
+ }
+ }
+
+ unsigned attributes;
+ JSCell* specificValue;
+ if ((thisObject->structure()->get(globalData, propertyName, attributes, specificValue) != WTF::notFound) && attributes & ReadOnly) {
+ if (slot.isStrictMode())
+ throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
+ return;
+ }
+
+ for (JSObject* obj = thisObject; ; obj = asObject(prototype)) {
+ if (JSValue gs = obj->getDirect(globalData, propertyName)) {
+ if (gs.isGetterSetter()) {
+ JSObject* setterFunc = asGetterSetter(gs)->setter();
+ if (!setterFunc) {
+ throwSetterError(exec);
+ return;
+ }
+
+ CallData callData;
+ CallType callType = setterFunc->methodTable()->getCallData(setterFunc, callData);
+ MarkedArgumentBuffer args;
+ args.append(value);
+
+ // If this is WebCore's global object then we need to substitute the shell.
+ call(exec, setterFunc, callType, callData, thisObject->methodTable()->toThisObject(thisObject, exec), 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;
+ }
+
+ if (!thisObject->putDirectInternal(globalData, propertyName, value, 0, true, slot, getJSFunction(value)) && slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return;
+}
+
+void JSObject::putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue value)
+{
+ PutPropertySlot slot;
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ thisObject->methodTable()->put(thisObject, exec, Identifier::from(exec, propertyName), value, slot);
+}
+
+void JSObject::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ PutPropertySlot slot;
+ object->putDirectInternal(exec->globalData(), propertyName, value, attributes, true, slot, getJSFunction(value));
+}
+
+void JSObject::putWithAttributes(JSGlobalData* globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ PutPropertySlot slot;
+ putDirectInternal(*globalData, propertyName, value, attributes, true, slot, getJSFunction(value));
+}
+
+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(JSCell* cell, ExecState* exec, const Identifier& propertyName)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+
+ if (!thisObject->staticFunctionsReified())
+ thisObject->reifyStaticFunctionsForDelete(exec);
+
+ unsigned attributes;
+ JSCell* specificValue;
+ if (thisObject->structure()->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound) {
+ if ((attributes & DontDelete))
+ return false;
+ thisObject->removeDirect(exec->globalData(), propertyName);
+ return true;
+ }
+
+ // Look in the static hashtable of properties
+ const HashEntry* entry = thisObject->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)->methodTable()->getOwnPropertySlot(const_cast<JSObject*>(this), exec, propertyName, slot);
+}
+
+bool JSObject::deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
+{
+ JSObject* thisObject = jsCast<JSObject*>(cell);
+ return thisObject->methodTable()->deleteProperty(thisObject, 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 = getCallData(function, callData);
+ if (callType == CallTypeNone)
+ return exec->exception();
+
+ // Prevent "toString" and "valueOf" from observing execution if an exception
+ // is pending.
+ if (exec->hadException())
+ return exec->exception();
+
+ JSValue result = call(exec, function, callType, callData, const_cast<JSObject*>(object), exec->emptyList());
+ ASSERT(!result.isGetterSetter());
+ if (exec->hadException())
+ return exec->exception();
+ if (result.isObject())
+ return JSValue();
+ return result;
+}
+
+bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
+{
+ result = methodTable()->defaultValue(this, exec, PreferNumber);
+ number = result.toNumber(exec);
+ return !result.isString();
+}
+
+// ECMA 8.6.2.6
+JSValue JSObject::defaultValue(const JSObject* object, ExecState* exec, PreferredPrimitiveType hint)
+{
+ // Must call toString first for Date objects.
+ if ((hint == PreferString) || (hint != PreferNumber && object->prototype() == exec->lexicalGlobalObject()->datePrototype())) {
+ JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
+ if (value)
+ return value;
+ value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
+ if (value)
+ return value;
+ } else {
+ JSValue value = callDefaultValueFunction(exec, object, exec->propertyNames().valueOf);
+ if (value)
+ return value;
+ value = callDefaultValueFunction(exec, object, exec->propertyNames().toString);
+ if (value)
+ return value;
+ }
+
+ ASSERT(!exec->hadException());
+
+ return throwError(exec, createTypeError(exec, "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(JSObject* thisObject, ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes)
+{
+ if (propertyName == exec->propertyNames().underscoreProto) {
+ // Defining a getter for __proto__ is silently ignored.
+ return;
+ }
+
+ JSValue object = thisObject->getDirect(exec->globalData(), propertyName);
+ if (object && object.isGetterSetter()) {
+ ASSERT(thisObject->structure()->hasGetterSetterProperties());
+ asGetterSetter(object)->setGetter(exec->globalData(), getterFunction);
+ return;
+ }
+
+ JSGlobalData& globalData = exec->globalData();
+ PutPropertySlot slot;
+ GetterSetter* getterSetter = GetterSetter::create(exec);
+ thisObject->putDirectInternal(globalData, propertyName, getterSetter, attributes | Getter, true, slot, 0);
+
+ // putDirect will change our Structure if we add a new property. For
+ // getters and setters, though, we also need to change our Structure
+ // if we override an existing non-getter or non-setter.
+ if (slot.type() != PutPropertySlot::NewProperty) {
+ if (!thisObject->structure()->isDictionary())
+ thisObject->setStructure(exec->globalData(), Structure::getterSetterTransition(globalData, thisObject->structure()));
+ }
+
+ thisObject->structure()->setHasGetterSetterProperties(true);
+ getterSetter->setGetter(globalData, getterFunction);
+}
+
+void JSObject::initializeGetterSetterProperty(ExecState* exec, const Identifier& propertyName, GetterSetter* getterSetter, unsigned attributes)
+{
+ // Set an inital property on an object; the property must not already exist & the attribute flags must be set correctly.
+ ASSERT(structure()->get(exec->globalData(), propertyName) == WTF::notFound);
+ ASSERT(static_cast<bool>(getterSetter->getter()) == static_cast<bool>(attributes & Getter));
+ ASSERT(static_cast<bool>(getterSetter->setter()) == static_cast<bool>(attributes & Setter));
+
+ JSGlobalData& globalData = exec->globalData();
+ PutPropertySlot slot;
+ putDirectInternal(globalData, propertyName, getterSetter, attributes | Getter, true, slot, 0);
+
+ // putDirect will change our Structure if we add a new property. For
+ // getters and setters, though, we also need to change our Structure
+ // if we override an existing non-getter or non-setter.
+ if (slot.type() != PutPropertySlot::NewProperty) {
+ if (!structure()->isDictionary())
+ setStructure(exec->globalData(), Structure::getterSetterTransition(globalData, structure()));
+ }
+
+ structure()->setHasGetterSetterProperties(true);
+}
+
+void JSObject::defineSetter(JSObject* thisObject, ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes)
+{
+ if (propertyName == exec->propertyNames().underscoreProto) {
+ // Defining a setter for __proto__ is silently ignored.
+ return;
+ }
+
+ JSValue object = thisObject->getDirect(exec->globalData(), propertyName);
+ if (object && object.isGetterSetter()) {
+ ASSERT(thisObject->structure()->hasGetterSetterProperties());
+ asGetterSetter(object)->setSetter(exec->globalData(), setterFunction);
+ return;
+ }
+
+ PutPropertySlot slot;
+ GetterSetter* getterSetter = GetterSetter::create(exec);
+ thisObject->putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Setter, true, slot, 0);
+
+ // putDirect will change our Structure if we add a new property. For
+ // getters and setters, though, we also need to change our Structure
+ // if we override an existing non-getter or non-setter.
+ if (slot.type() != PutPropertySlot::NewProperty) {
+ if (!thisObject->structure()->isDictionary())
+ thisObject->setStructure(exec->globalData(), Structure::getterSetterTransition(exec->globalData(), thisObject->structure()));
+ }
+
+ thisObject->structure()->setHasGetterSetterProperties(true);
+ getterSetter->setSetter(exec->globalData(), setterFunction);
+}
+
+JSValue JSObject::lookupGetter(ExecState* exec, const Identifier& propertyName)
+{
+ PropertyDescriptor descriptor;
+ if (!getPropertyDescriptor(exec, propertyName, descriptor))
+ return jsUndefined();
+
+ if (!descriptor.getterPresent())
+ return jsUndefined();
+
+ return descriptor.getter();
+}
+
+JSValue JSObject::lookupSetter(ExecState* exec, const Identifier& propertyName)
+{
+ PropertyDescriptor descriptor;
+ if (!getPropertyDescriptor(exec, propertyName, descriptor))
+ return jsUndefined();
+
+ if (!descriptor.setterPresent())
+ return jsUndefined();
+
+ return descriptor.setter();
+}
+
+bool JSObject::hasInstance(JSObject*, ExecState* exec, JSValue value, JSValue proto)
+{
+ if (!value.isObject())
+ return false;
+
+ if (!proto.isObject()) {
+ throwError(exec, createTypeError(exec, "instanceof called on an object with an invalid prototype property."));
+ return false;
+ }
+
+ JSObject* object = asObject(value);
+ while ((object = object->prototype().getObject())) {
+ if (proto == object)
+ return true;
+ }
+ return false;
+}
+
+bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const
+{
+ PropertyDescriptor descriptor;
+ if (!const_cast<JSObject*>(this)->methodTable()->getOwnPropertyDescriptor(const_cast<JSObject*>(this), exec, propertyName, descriptor))
+ return false;
+ return descriptor.enumerable();
+}
+
+bool JSObject::getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificValue) const
+{
+ unsigned attributes;
+ if (structure()->get(exec->globalData(), propertyName, attributes, specificValue) != WTF::notFound)
+ return true;
+
+ // This could be a function within the static table? - should probably
+ // also look in the hash? This currently should not be a problem, since
+ // we've currently always call 'get' first, which should have populated
+ // the normal storage.
+ return false;
+}
+
+void JSObject::getPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ object->methodTable()->getOwnPropertyNames(object, exec, propertyNames, mode);
+
+ if (object->prototype().isNull())
+ return;
+
+ JSObject* prototype = asObject(object->prototype());
+ while(1) {
+ if (prototype->structure()->typeInfo().overridesGetPropertyNames()) {
+ prototype->methodTable()->getPropertyNames(prototype, exec, propertyNames, mode);
+ break;
+ }
+ prototype->methodTable()->getOwnPropertyNames(prototype, exec, propertyNames, mode);
+ JSValue nextProto = prototype->prototype();
+ if (nextProto.isNull())
+ break;
+ prototype = asObject(nextProto);
+ }
+}
+
+void JSObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ object->structure()->getPropertyNamesFromStructure(exec->globalData(), propertyNames, mode);
+ if (!object->staticFunctionsReified())
+ getClassPropertyNames(exec, object->classInfo(), propertyNames, mode);
+}
+
+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::toThisObject(JSCell* cell, ExecState*)
+{
+ return static_cast<JSObject*>(cell);
+}
+
+JSObject* JSObject::unwrappedObject()
+{
+ if (isGlobalThis())
+ return static_cast<JSGlobalThis*>(this)->unwrappedObject();
+ return this;
+}
+
+void JSObject::seal(JSGlobalData& globalData)
+{
+ if (isSealed(globalData))
+ return;
+ preventExtensions(globalData);
+ setStructure(globalData, Structure::sealTransition(globalData, structure()));
+}
+
+void JSObject::freeze(JSGlobalData& globalData)
+{
+ if (isFrozen(globalData))
+ return;
+ preventExtensions(globalData);
+ setStructure(globalData, Structure::freezeTransition(globalData, structure()));
+}
+
+void JSObject::preventExtensions(JSGlobalData& globalData)
+{
+ if (isExtensible())
+ setStructure(globalData, Structure::preventExtensionsTransition(globalData, structure()));
+}
+
+// This presently will flatten to an uncachable dictionary; this is suitable
+// for use in delete, we may want to do something different elsewhere.
+void JSObject::reifyStaticFunctionsForDelete(ExecState* exec)
+{
+ ASSERT(!staticFunctionsReified());
+ JSGlobalData& globalData = exec->globalData();
+
+ // If this object's ClassInfo has no static properties, then nothing to reify!
+ // We can safely set the flag to avoid the expensive check again in the future.
+ if (!classInfo()->hasStaticProperties()) {
+ structure()->setStaticFunctionsReified();
+ return;
+ }
+
+ if (!structure()->isUncacheableDictionary())
+ setStructure(globalData, Structure::toUncacheableDictionaryTransition(globalData, structure()));
+
+ for (const ClassInfo* info = classInfo(); info; info = info->parentClass) {
+ const HashTable* hashTable = info->propHashTable(globalObject()->globalExec());
+ if (!hashTable)
+ continue;
+ PropertySlot slot;
+ for (HashTable::ConstIterator iter = hashTable->begin(globalData); iter != hashTable->end(globalData); ++iter) {
+ if (iter->attributes() & Function)
+ setUpStaticFunctionSlot(globalObject()->globalExec(), *iter, this, Identifier(&globalData, iter->key()), slot);
+ }
+ }
+
+ structure()->setStaticFunctionsReified();
+}
+
+void JSObject::removeDirect(JSGlobalData& globalData, const Identifier& propertyName)
+{
+ if (structure()->get(globalData, propertyName) == WTF::notFound)
+ return;
+
+ size_t offset;
+ if (structure()->isUncacheableDictionary()) {
+ offset = structure()->removePropertyWithoutTransition(globalData, propertyName);
+ if (offset != WTF::notFound)
+ putUndefinedAtDirectOffset(offset);
+ return;
+ }
+
+ setStructure(globalData, Structure::removePropertyTransition(globalData, structure(), propertyName, offset));
+ if (offset != WTF::notFound)
+ putUndefinedAtDirectOffset(offset);
+}
+
+NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, WriteBarrierBase<Unknown>* location)
+{
+ if (JSObject* getterFunction = asGetterSetter(location->get())->getter()) {
+ if (!structure()->isDictionary())
+ slot.setCacheableGetterSlot(this, getterFunction, offsetForLocation(location));
+ else
+ slot.setGetterSlot(getterFunction);
+ } else
+ slot.setUndefined();
+}
+
+Structure* JSObject::createInheritorID(JSGlobalData& globalData)
+{
+ m_inheritorID.set(globalData, this, createEmptyObjectStructure(globalData, structure()->globalObject(), this));
+ ASSERT(m_inheritorID->isEmpty());
+ return m_inheritorID.get();
+}
+
+void JSObject::allocatePropertyStorage(JSGlobalData& globalData, size_t oldSize, size_t newSize)
+{
+ ASSERT(newSize > oldSize);
+
+ // It's important that this function not rely on structure(), since
+ // we might be in the middle of a transition.
+ PropertyStorage newPropertyStorage = 0;
+ newPropertyStorage = new WriteBarrierBase<Unknown>[newSize];
+
+ PropertyStorage oldPropertyStorage = m_propertyStorage.get();
+ ASSERT(newPropertyStorage);
+
+ for (unsigned i = 0; i < oldSize; ++i)
+ newPropertyStorage[i] = oldPropertyStorage[i];
+
+ if (isUsingInlineStorage())
+ Heap::heap(this)->addFinalizer(this, &finalize);
+ else
+ delete [] oldPropertyStorage;
+
+ m_propertyStorage.set(globalData, this, newPropertyStorage);
+}
+
+bool JSObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ unsigned attributes = 0;
+ JSCell* cell = 0;
+ size_t offset = object->structure()->get(exec->globalData(), propertyName, attributes, cell);
+ if (offset == WTF::notFound)
+ return false;
+ descriptor.setDescriptor(object->getDirectOffset(offset), attributes);
+ return true;
+}
+
+bool JSObject::getPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ JSObject* object = this;
+ while (true) {
+ if (object->methodTable()->getOwnPropertyDescriptor(object, exec, propertyName, descriptor))
+ return true;
+ JSValue prototype = object->prototype();
+ if (!prototype.isObject())
+ return false;
+ object = asObject(prototype);
+ }
+}
+
+static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& propertyName, PropertyDescriptor& descriptor, unsigned attributes, const PropertyDescriptor& oldDescriptor)
+{
+ if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) {
+ if (descriptor.isGenericDescriptor() && oldDescriptor.isAccessorDescriptor()) {
+ GetterSetter* accessor = GetterSetter::create(exec);
+ if (oldDescriptor.getter()) {
+ attributes |= Getter;
+ accessor->setGetter(exec->globalData(), asObject(oldDescriptor.getter()));
+ }
+ if (oldDescriptor.setter()) {
+ attributes |= Setter;
+ accessor->setSetter(exec->globalData(), asObject(oldDescriptor.setter()));
+ }
+ target->methodTable()->putWithAttributes(target, exec, propertyName, accessor, attributes);
+ return true;
+ }
+ JSValue newValue = jsUndefined();
+ if (descriptor.value())
+ newValue = descriptor.value();
+ else if (oldDescriptor.value())
+ newValue = oldDescriptor.value();
+ target->methodTable()->putWithAttributes(target, exec, propertyName, newValue, attributes & ~(Getter | Setter));
+ return true;
+ }
+ attributes &= ~ReadOnly;
+ if (descriptor.getter() && descriptor.getter().isObject())
+ target->methodTable()->defineGetter(target, exec, propertyName, asObject(descriptor.getter()), attributes);
+ if (exec->hadException())
+ return false;
+ if (descriptor.setter() && descriptor.setter().isObject())
+ target->methodTable()->defineSetter(target, exec, propertyName, asObject(descriptor.setter()), attributes);
+ return !exec->hadException();
+}
+
+bool JSObject::defineOwnProperty(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException)
+{
+ // If we have a new property we can just put it on normally
+ PropertyDescriptor current;
+ if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, propertyName, current)) {
+ // unless extensions are prevented!
+ if (!object->isExtensible()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to define property on object that is not extensible."));
+ return false;
+ }
+ PropertyDescriptor oldDescriptor;
+ oldDescriptor.setValue(jsUndefined());
+ return putDescriptor(exec, object, propertyName, descriptor, descriptor.attributes(), oldDescriptor);
+ }
+
+ if (descriptor.isEmpty())
+ return true;
+
+ if (current.equalTo(exec, descriptor))
+ return true;
+
+ // Filter out invalid changes
+ if (!current.configurable()) {
+ if (descriptor.configurable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to configurable attribute of unconfigurable property."));
+ return false;
+ }
+ if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change enumerable attribute of unconfigurable property."));
+ return false;
+ }
+ }
+
+ // A generic descriptor is simply changing the attributes of an existing property
+ if (descriptor.isGenericDescriptor()) {
+ if (!current.attributesEqual(descriptor)) {
+ object->methodTable()->deleteProperty(object, exec, propertyName);
+ putDescriptor(exec, object, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
+ }
+ return true;
+ }
+
+ // Changing between a normal property or an accessor property
+ if (descriptor.isDataDescriptor() != current.isDataDescriptor()) {
+ if (!current.configurable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change access mechanism for an unconfigurable property."));
+ return false;
+ }
+ object->methodTable()->deleteProperty(object, exec, propertyName);
+ return putDescriptor(exec, object, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
+ }
+
+ // Changing the value and attributes of an existing property
+ if (descriptor.isDataDescriptor()) {
+ if (!current.configurable()) {
+ if (!current.writable() && descriptor.writable()) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change writable attribute of unconfigurable property."));
+ return false;
+ }
+ if (!current.writable()) {
+ if (descriptor.value() || !JSValue::strictEqual(exec, current.value(), descriptor.value())) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change value of a readonly property."));
+ return false;
+ }
+ }
+ } else if (current.attributesEqual(descriptor)) {
+ if (!descriptor.value())
+ return true;
+ PutPropertySlot slot;
+ object->methodTable()->put(object, exec, propertyName, descriptor.value(), slot);
+ if (exec->hadException())
+ return false;
+ return true;
+ }
+ object->methodTable()->deleteProperty(object, exec, propertyName);
+ return putDescriptor(exec, object, propertyName, descriptor, current.attributesWithOverride(descriptor), current);
+ }
+
+ // Changing the accessor functions of an existing accessor property
+ ASSERT(descriptor.isAccessorDescriptor());
+ if (!current.configurable()) {
+ if (descriptor.setterPresent() && !(current.setterPresent() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change the setter of an unconfigurable property."));
+ return false;
+ }
+ if (descriptor.getterPresent() && !(current.getterPresent() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) {
+ if (throwException)
+ throwError(exec, createTypeError(exec, "Attempting to change the getter of an unconfigurable property."));
+ return false;
+ }
+ }
+ JSValue accessor = object->getDirect(exec->globalData(), propertyName);
+ if (!accessor)
+ return false;
+ GetterSetter* getterSetter = asGetterSetter(accessor);
+ if (current.attributesEqual(descriptor)) {
+ if (descriptor.setter())
+ getterSetter->setSetter(exec->globalData(), asObject(descriptor.setter()));
+ if (descriptor.getter())
+ getterSetter->setGetter(exec->globalData(), asObject(descriptor.getter()));
+ return true;
+ }
+ object->methodTable()->deleteProperty(object, exec, propertyName);
+ unsigned attrs = current.attributesWithOverride(descriptor);
+ if (descriptor.setter())
+ attrs |= Setter;
+ if (descriptor.getter())
+ attrs |= Getter;
+ object->putDirect(exec->globalData(), propertyName, getterSetter, attrs);
+ return true;
+}
+
+JSObject* throwTypeError(ExecState* exec, const UString& message)
+{
+ return throwError(exec, createTypeError(exec, message));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSObject.h b/Source/JavaScriptCore/runtime/JSObject.h
new file mode 100644
index 000000000..e26012dd9
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSObject.h
@@ -0,0 +1,879 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef JSObject_h
+#define JSObject_h
+
+#include "ArgList.h"
+#include "ClassInfo.h"
+#include "CommonIdentifiers.h"
+#include "CallFrame.h"
+#include "JSCell.h"
+#include "PropertySlot.h"
+#include "PutPropertySlot.h"
+#include "ScopeChain.h"
+#include "StorageBarrier.h"
+#include "Structure.h"
+#include "JSGlobalData.h"
+#include "JSString.h"
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+ inline JSCell* getJSFunction(JSValue value)
+ {
+ if (value.isCell() && (value.asCell()->structure()->typeInfo().type() == JSFunctionType))
+ return value.asCell();
+ return 0;
+ }
+
+ class GetterSetter;
+ class HashEntry;
+ class InternalFunction;
+ class MarkedBlock;
+ class PropertyDescriptor;
+ class PropertyNameArray;
+ class Structure;
+ struct HashTable;
+
+ JSObject* throwTypeError(ExecState*, const UString&);
+ extern JS_EXPORTDATA const char* StrictModeReadonlyPropertyWriteError;
+
+ // ECMA 262-3 8.6.1
+ // Property attributes
+ enum Attribute {
+ None = 0,
+ ReadOnly = 1 << 1, // property can be only read, not written
+ DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
+ DontDelete = 1 << 3, // property can't be deleted
+ Function = 1 << 4, // property is a function - only used by static hashtables
+ Getter = 1 << 5, // property is a getter
+ Setter = 1 << 6 // property is a setter
+ };
+
+ class JSObject : public JSCell {
+ friend class BatchedTransitionOptimizer;
+ friend class JIT;
+ friend class JSCell;
+ friend class MarkedBlock;
+ friend bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot);
+
+ public:
+ typedef JSCell Base;
+
+ static void destroy(JSCell*);
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ static UString className(const JSObject*);
+
+ static void finalize(JSCell*);
+
+ JSValue prototype() const;
+ void setPrototype(JSGlobalData&, JSValue prototype);
+ bool setPrototypeWithCycleCheck(JSGlobalData&, JSValue prototype);
+
+ Structure* inheritorID(JSGlobalData&);
+
+ 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&);
+ bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+ static void putByIndex(JSCell*, ExecState*, unsigned propertyName, JSValue);
+
+ static void putWithAttributes(JSObject*, ExecState*, const Identifier& propertyName, JSValue, unsigned attributes);
+ void putWithAttributes(JSGlobalData*, const Identifier& propertyName, JSValue, 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;
+
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
+ static bool deletePropertyByIndex(JSCell*, ExecState*, unsigned propertyName);
+
+ static JSValue defaultValue(const JSObject*, ExecState*, PreferredPrimitiveType);
+
+ static bool hasInstance(JSObject*, ExecState*, JSValue, JSValue prototypeProperty);
+
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+ static void getPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
+ JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const;
+ bool toBoolean(ExecState*) const;
+ bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
+ double toNumber(ExecState*) const;
+ UString toString(ExecState*) const;
+
+ // NOTE: JSObject and its subclasses must be able to gracefully handle ExecState* = 0,
+ // because this call may come from inside the compiler.
+ static JSObject* toThisObject(JSCell*, ExecState*);
+ JSObject* unwrappedObject();
+
+ bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const;
+
+ // This get function only looks at the property map.
+ JSValue getDirect(JSGlobalData& globalData, const Identifier& propertyName) const
+ {
+ size_t offset = structure()->get(globalData, propertyName);
+ return offset != WTF::notFound ? getDirectOffset(offset) : JSValue();
+ }
+
+ WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName)
+ {
+ size_t offset = structure()->get(globalData, propertyName);
+ return offset != WTF::notFound ? locationForOffset(offset) : 0;
+ }
+
+ WriteBarrierBase<Unknown>* getDirectLocation(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes)
+ {
+ JSCell* specificFunction;
+ size_t offset = structure()->get(globalData, propertyName, attributes, specificFunction);
+ return offset != WTF::notFound ? locationForOffset(offset) : 0;
+ }
+
+ size_t offsetForLocation(WriteBarrierBase<Unknown>* location) const
+ {
+ return location - propertyStorage();
+ }
+
+ void transitionTo(JSGlobalData&, Structure*);
+
+ void removeDirect(JSGlobalData&, const Identifier& propertyName);
+ bool hasCustomProperties() { return structure()->didTransition(); }
+ bool hasGetterSetterProperties() { return structure()->hasGetterSetterProperties(); }
+
+ bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&);
+ void putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0);
+ bool putDirect(JSGlobalData&, const Identifier& propertyName, JSValue, PutPropertySlot&);
+
+ void putDirectWithoutTransition(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr = 0);
+
+ // Fast access to known property offsets.
+ JSValue getDirectOffset(size_t offset) const { return propertyStorage()[offset].get(); }
+ void putDirectOffset(JSGlobalData& globalData, size_t offset, JSValue value) { propertyStorage()[offset].set(globalData, this, value); }
+ void putUndefinedAtDirectOffset(size_t offset) { propertyStorage()[offset].setUndefined(); }
+
+ void fillGetterPropertySlot(PropertySlot&, WriteBarrierBase<Unknown>* location);
+ void initializeGetterSetterProperty(ExecState*, const Identifier&, GetterSetter*, unsigned attributes);
+
+ static void defineGetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0);
+ static void defineSetter(JSObject*, ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0);
+ JSValue lookupGetter(ExecState*, const Identifier& propertyName);
+ JSValue lookupSetter(ExecState*, const Identifier& propertyName);
+ static bool defineOwnProperty(JSObject*, ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow);
+
+ bool isGlobalObject() const;
+ bool isVariableObject() const;
+ bool isActivationObject() const;
+ bool isErrorInstance() const;
+ bool isGlobalThis() const;
+
+ void seal(JSGlobalData&);
+ void freeze(JSGlobalData&);
+ void preventExtensions(JSGlobalData&);
+ bool isSealed(JSGlobalData& globalData) { return structure()->isSealed(globalData); }
+ bool isFrozen(JSGlobalData& globalData) { return structure()->isFrozen(globalData); }
+ bool isExtensible() { return structure()->isExtensible(); }
+
+ bool staticFunctionsReified() { return structure()->staticFunctionsReified(); }
+ void reifyStaticFunctionsForDelete(ExecState* exec);
+
+ void allocatePropertyStorage(JSGlobalData&, size_t oldSize, size_t newSize);
+ bool isUsingInlineStorage() const { return static_cast<const void*>(m_propertyStorage.get()) == static_cast<const void*>(this + 1); }
+
+ void* addressOfPropertyStorage()
+ {
+ return &m_propertyStorage;
+ }
+
+ static const unsigned baseExternalStorageCapacity = 16;
+
+ void flattenDictionaryObject(JSGlobalData& globalData)
+ {
+ structure()->flattenDictionaryStructure(globalData, this);
+ }
+
+ JSGlobalObject* globalObject() const
+ {
+ ASSERT(structure()->globalObject());
+ ASSERT(!isGlobalObject() || ((JSObject*)structure()->globalObject()) == this);
+ return structure()->globalObject();
+ }
+
+ static size_t offsetOfInlineStorage();
+ static size_t offsetOfPropertyStorage();
+ static size_t offsetOfInheritorID();
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ protected:
+ void finishCreation(JSGlobalData& globalData, PropertyStorage inlineStorage)
+ {
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+ ASSERT(structure()->propertyStorageCapacity() < baseExternalStorageCapacity);
+ ASSERT(structure()->isEmpty());
+ ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype()));
+ ASSERT_UNUSED(inlineStorage, static_cast<void*>(inlineStorage) == static_cast<void*>(this + 1));
+ ASSERT(structure()->isObject());
+ ASSERT(classInfo());
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static const unsigned StructureFlags = 0;
+
+ // To instantiate objects you likely want JSFinalObject, below.
+ // To create derived types you likely want JSNonFinalObject, below.
+ JSObject(JSGlobalData&, Structure*, PropertyStorage inlineStorage);
+
+ private:
+ // Nobody should ever ask any of these questions on something already known to be a JSObject.
+ using JSCell::isAPIValueWrapper;
+ using JSCell::isGetterSetter;
+ void getObject();
+ void getString(ExecState* exec);
+ void isObject();
+ void isString();
+
+ ConstPropertyStorage propertyStorage() const { return m_propertyStorage.get(); }
+ PropertyStorage propertyStorage() { return m_propertyStorage.get(); }
+
+ const WriteBarrierBase<Unknown>* locationForOffset(size_t offset) const
+ {
+ return &propertyStorage()[offset];
+ }
+
+ WriteBarrierBase<Unknown>* locationForOffset(size_t offset)
+ {
+ return &propertyStorage()[offset];
+ }
+
+ bool putDirectInternal(JSGlobalData&, const Identifier& propertyName, JSValue, unsigned attr, bool checkReadOnly, PutPropertySlot&, JSCell*);
+
+ bool inlineGetOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
+
+ const HashEntry* findPropertyHashEntry(ExecState*, const Identifier& propertyName) const;
+ Structure* createInheritorID(JSGlobalData&);
+
+ StorageBarrier m_propertyStorage;
+ WriteBarrier<Structure> m_inheritorID;
+ };
+
+
+#if USE(JSVALUE32_64)
+#define JSNonFinalObject_inlineStorageCapacity 4
+#define JSFinalObject_inlineStorageCapacity 6
+#else
+#define JSNonFinalObject_inlineStorageCapacity 2
+#define JSFinalObject_inlineStorageCapacity 4
+#endif
+
+COMPILE_ASSERT((JSFinalObject_inlineStorageCapacity >= JSNonFinalObject_inlineStorageCapacity), final_storage_is_at_least_as_large_as_non_final);
+
+ // JSNonFinalObject is a type of JSObject that has some internal storage,
+ // but also preserves some space in the collector cell for additional
+ // data members in derived types.
+ class JSNonFinalObject : public JSObject {
+ friend class JSObject;
+
+ public:
+ typedef JSObject Base;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static void destroy(JSCell*);
+
+ protected:
+ explicit JSNonFinalObject(JSGlobalData& globalData, Structure* structure)
+ : JSObject(globalData, structure, m_inlineStorage)
+ {
+ }
+
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData, m_inlineStorage);
+ ASSERT(!(OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage) % sizeof(double)));
+ ASSERT(this->structure()->propertyStorageCapacity() == JSNonFinalObject_inlineStorageCapacity);
+ ASSERT(classInfo());
+ }
+
+ private:
+ WriteBarrier<Unknown> m_inlineStorage[JSNonFinalObject_inlineStorageCapacity];
+ };
+
+ // JSFinalObject is a type of JSObject that contains sufficent internal
+ // storage to fully make use of the colloctor cell containing it.
+ class JSFinalObject : public JSObject {
+ friend class JSObject;
+
+ public:
+ typedef JSObject Base;
+
+ static JSFinalObject* create(ExecState* exec, Structure* structure)
+ {
+ JSFinalObject* finalObject = new (NotNull, allocateCell<JSFinalObject>(*exec->heap())) JSFinalObject(exec->globalData(), structure);
+ finalObject->finishCreation(exec->globalData());
+ return finalObject;
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(FinalObjectType, StructureFlags), &s_info);
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ protected:
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData, m_inlineStorage);
+ ASSERT(!(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) % sizeof(double)));
+ ASSERT(this->structure()->propertyStorageCapacity() == JSFinalObject_inlineStorageCapacity);
+ ASSERT(classInfo());
+ }
+
+ static void destroy(JSCell*);
+
+ private:
+ explicit JSFinalObject(JSGlobalData& globalData, Structure* structure)
+ : JSObject(globalData, structure, m_inlineStorage)
+ {
+ }
+
+ static const unsigned StructureFlags = JSObject::StructureFlags;
+
+ WriteBarrierBase<Unknown> m_inlineStorage[JSFinalObject_inlineStorageCapacity];
+ };
+
+inline bool isJSFinalObject(JSCell* cell)
+{
+ return cell->classInfo() == &JSFinalObject::s_info;
+}
+
+inline bool isJSFinalObject(JSValue value)
+{
+ return value.isCell() && isJSFinalObject(value.asCell());
+}
+
+inline size_t JSObject::offsetOfInlineStorage()
+{
+ ASSERT(OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage) == OBJECT_OFFSETOF(JSNonFinalObject, m_inlineStorage));
+ return OBJECT_OFFSETOF(JSFinalObject, m_inlineStorage);
+}
+
+inline size_t JSObject::offsetOfPropertyStorage()
+{
+ return OBJECT_OFFSETOF(JSObject, m_propertyStorage);
+}
+
+inline size_t JSObject::offsetOfInheritorID()
+{
+ return OBJECT_OFFSETOF(JSObject, m_inheritorID);
+}
+
+inline bool JSObject::isGlobalObject() const
+{
+ return structure()->typeInfo().type() == GlobalObjectType;
+}
+
+inline bool JSObject::isVariableObject() const
+{
+ return structure()->typeInfo().type() >= VariableObjectType;
+}
+
+inline bool JSObject::isActivationObject() const
+{
+ return structure()->typeInfo().type() == ActivationObjectType;
+}
+
+inline bool JSObject::isErrorInstance() const
+{
+ return structure()->typeInfo().type() == ErrorInstanceType;
+}
+
+inline bool JSObject::isGlobalThis() const
+{
+ return structure()->typeInfo().type() == GlobalThisType;
+}
+
+inline JSObject* constructEmptyObject(ExecState* exec, Structure* structure)
+{
+ return JSFinalObject::create(exec, structure);
+}
+
+inline CallType getCallData(JSValue value, CallData& callData)
+{
+ CallType result = value.isCell() ? value.asCell()->methodTable()->getCallData(value.asCell(), callData) : CallTypeNone;
+ ASSERT(result == CallTypeNone || value.isValidCallee());
+ return result;
+}
+
+inline ConstructType getConstructData(JSValue value, ConstructData& constructData)
+{
+ ConstructType result = value.isCell() ? value.asCell()->methodTable()->getConstructData(value.asCell(), constructData) : ConstructTypeNone;
+ ASSERT(result == ConstructTypeNone || value.isValidCallee());
+ return result;
+}
+
+inline Structure* createEmptyObjectStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+{
+ return JSFinalObject::createStructure(globalData, globalObject, prototype);
+}
+
+inline JSObject* asObject(JSCell* cell)
+{
+ ASSERT(cell->isObject());
+ return static_cast<JSObject*>(cell);
+}
+
+inline JSObject* asObject(JSValue value)
+{
+ return asObject(value.asCell());
+}
+
+inline JSObject::JSObject(JSGlobalData& globalData, Structure* structure, PropertyStorage inlineStorage)
+ : JSCell(globalData, structure)
+ , m_propertyStorage(globalData, this, inlineStorage)
+{
+}
+
+inline JSValue JSObject::prototype() const
+{
+ return structure()->storedPrototype();
+}
+
+inline bool JSObject::setPrototypeWithCycleCheck(JSGlobalData& globalData, JSValue prototype)
+{
+ JSValue nextPrototypeValue = prototype;
+ while (nextPrototypeValue && nextPrototypeValue.isObject()) {
+ JSObject* nextPrototype = asObject(nextPrototypeValue)->unwrappedObject();
+ if (nextPrototype == this)
+ return false;
+ nextPrototypeValue = nextPrototype->prototype();
+ }
+ setPrototype(globalData, prototype);
+ return true;
+}
+
+inline void JSObject::setPrototype(JSGlobalData& globalData, JSValue prototype)
+{
+ ASSERT(prototype);
+ setStructure(globalData, Structure::changePrototypeTransition(globalData, structure(), prototype));
+}
+
+inline Structure* JSObject::inheritorID(JSGlobalData& globalData)
+{
+ if (m_inheritorID) {
+ ASSERT(m_inheritorID->isEmpty());
+ return m_inheritorID.get();
+ }
+ return createInheritorID(globalData);
+}
+
+inline bool Structure::isUsingInlineStorage() const
+{
+ return propertyStorageCapacity() < JSObject::baseExternalStorageCapacity;
+}
+
+inline bool JSCell::inherits(const ClassInfo* info) const
+{
+ return classInfo()->isSubClassOf(info);
+}
+
+inline const MethodTable* JSCell::methodTable() const
+{
+ return &classInfo()->methodTable;
+}
+
+// this method is here to be after the inline declaration of JSCell::inherits
+inline bool JSValue::inherits(const ClassInfo* classInfo) const
+{
+ return isCell() && asCell()->inherits(classInfo);
+}
+
+inline JSObject* JSValue::toThisObject(ExecState* exec) const
+{
+ return isCell() ? asCell()->methodTable()->toThisObject(asCell(), exec) : toThisObjectSlowCase(exec);
+}
+
+ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (WriteBarrierBase<Unknown>* location = getDirectLocation(exec->globalData(), propertyName)) {
+ if (structure()->hasGetterSetterProperties() && location->isGetterSetter())
+ fillGetterPropertySlot(slot, location);
+ else
+ slot.setValue(this, location->get(), offsetForLocation(location));
+ return true;
+ }
+
+ // non-standard Netscape extension
+ if (propertyName == exec->propertyNames().underscoreProto) {
+ slot.setValue(prototype());
+ return true;
+ }
+
+ return false;
+}
+
+// It may seem crazy to inline a function this large, especially a virtual function,
+// but it makes a big difference to property lookup that derived classes can inline their
+// base class call to this.
+ALWAYS_INLINE bool JSObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return jsCast<JSObject*>(cell)->inlineGetOwnPropertySlot(exec, propertyName, slot);
+}
+
+ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (!structure()->typeInfo().overridesGetOwnPropertySlot())
+ return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot);
+ return methodTable()->getOwnPropertySlot(this, exec, propertyName, slot);
+}
+
+// Fast call to get a property where we may not yet have converted the string to an
+// identifier. The first time we perform a property access with a given string, try
+// performing the property map lookup without forming an identifier. We detect this
+// case by checking whether the hash has yet been set for this string.
+ALWAYS_INLINE JSValue JSCell::fastGetOwnProperty(ExecState* exec, const UString& name)
+{
+ if (!structure()->typeInfo().overridesGetOwnPropertySlot() && !structure()->hasGetterSetterProperties()) {
+ size_t offset = name.impl()->hasHash()
+ ? structure()->get(exec->globalData(), Identifier(exec, name))
+ : structure()->get(exec->globalData(), name);
+ if (offset != WTF::notFound)
+ return asObject(this)->locationForOffset(offset)->get();
+ }
+ return JSValue();
+}
+
+// It may seem crazy to inline a function this large but it makes a big difference
+// since this is function very hot in variable lookup
+ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, 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);
+ }
+}
+
+ALWAYS_INLINE bool JSObject::getPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ JSObject* object = this;
+ while (true) {
+ if (object->methodTable()->getOwnPropertySlotByIndex(object, 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 bool JSObject::putDirectInternal(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot, JSCell* specificFunction)
+{
+ ASSERT(value);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+
+ if (structure()->isDictionary()) {
+ unsigned currentAttributes;
+ JSCell* currentSpecificFunction;
+ size_t offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
+ if (offset != WTF::notFound) {
+ // If there is currently a specific function, and there now either isn't,
+ // or the new value is different, then despecify.
+ if (currentSpecificFunction && (specificFunction != currentSpecificFunction))
+ structure()->despecifyDictionaryFunction(globalData, propertyName);
+ if (checkReadOnly && currentAttributes & ReadOnly)
+ return false;
+
+ putDirectOffset(globalData, offset, value);
+ // At this point, the objects structure only has a specific value set if previously there
+ // had been one set, and if the new value being specified is the same (otherwise we would
+ // have despecified, above). So, if currentSpecificFunction is not set, or if the new
+ // value is different (or there is no new value), then the slot now has no value - and
+ // as such it is cachable.
+ // If there was previously a value, and the new value is the same, then we cannot cache.
+ if (!currentSpecificFunction || (specificFunction != currentSpecificFunction))
+ slot.setExistingProperty(this, offset);
+ return true;
+ }
+
+ if (checkReadOnly && !isExtensible())
+ return false;
+
+ size_t currentCapacity = structure()->propertyStorageCapacity();
+ offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, specificFunction);
+ if (currentCapacity != structure()->propertyStorageCapacity())
+ allocatePropertyStorage(globalData, currentCapacity, structure()->propertyStorageCapacity());
+
+ ASSERT(offset < structure()->propertyStorageCapacity());
+ putDirectOffset(globalData, offset, value);
+ // See comment on setNewProperty call below.
+ if (!specificFunction)
+ slot.setNewProperty(this, offset);
+ return true;
+ }
+
+ size_t offset;
+ size_t currentCapacity = structure()->propertyStorageCapacity();
+ if (Structure* structure = Structure::addPropertyTransitionToExistingStructure(this->structure(), propertyName, attributes, specificFunction, offset)) {
+ if (currentCapacity != structure->propertyStorageCapacity())
+ allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
+
+ ASSERT(offset < structure->propertyStorageCapacity());
+ setStructure(globalData, structure);
+ putDirectOffset(globalData, offset, value);
+ // This is a new property; transitions with specific values are not currently cachable,
+ // so leave the slot in an uncachable state.
+ if (!specificFunction)
+ slot.setNewProperty(this, offset);
+ return true;
+ }
+
+ unsigned currentAttributes;
+ JSCell* currentSpecificFunction;
+ offset = structure()->get(globalData, propertyName, currentAttributes, currentSpecificFunction);
+ if (offset != WTF::notFound) {
+ if (checkReadOnly && currentAttributes & ReadOnly)
+ return false;
+
+ // There are three possibilities here:
+ // (1) There is an existing specific value set, and we're overwriting with *the same value*.
+ // * Do nothing - no need to despecify, but that means we can't cache (a cached
+ // put could write a different value). Leave the slot in an uncachable state.
+ // (2) There is a specific value currently set, but we're writing a different value.
+ // * First, we have to despecify. Having done so, this is now a regular slot
+ // with no specific value, so go ahead & cache like normal.
+ // (3) Normal case, there is no specific value set.
+ // * Go ahead & cache like normal.
+ if (currentSpecificFunction) {
+ // case (1) Do the put, then return leaving the slot uncachable.
+ if (specificFunction == currentSpecificFunction) {
+ putDirectOffset(globalData, offset, value);
+ return true;
+ }
+ // case (2) Despecify, fall through to (3).
+ setStructure(globalData, Structure::despecifyFunctionTransition(globalData, structure(), propertyName));
+ }
+
+ // case (3) set the slot, do the put, return.
+ slot.setExistingProperty(this, offset);
+ putDirectOffset(globalData, offset, value);
+ return true;
+ }
+
+ if (checkReadOnly && !isExtensible())
+ return false;
+
+ Structure* structure = Structure::addPropertyTransition(globalData, this->structure(), propertyName, attributes, specificFunction, offset);
+
+ if (currentCapacity != structure->propertyStorageCapacity())
+ allocatePropertyStorage(globalData, currentCapacity, structure->propertyStorageCapacity());
+
+ ASSERT(offset < structure->propertyStorageCapacity());
+ setStructure(globalData, structure);
+ putDirectOffset(globalData, offset, value);
+ // This is a new property; transitions with specific values are not currently cachable,
+ // so leave the slot in an uncachable state.
+ if (!specificFunction)
+ slot.setNewProperty(this, offset);
+ return true;
+}
+
+inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot)
+{
+ ASSERT(value);
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+
+ return putDirectInternal(globalData, propertyName, value, attributes, checkReadOnly, slot, getJSFunction(value));
+}
+
+inline void JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ PutPropertySlot slot;
+ putDirectInternal(globalData, propertyName, value, attributes, false, slot, getJSFunction(value));
+}
+
+inline bool JSObject::putDirect(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ return putDirectInternal(globalData, propertyName, value, 0, false, slot, getJSFunction(value));
+}
+
+inline void JSObject::putDirectWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ size_t currentCapacity = structure()->propertyStorageCapacity();
+ size_t offset = structure()->addPropertyWithoutTransition(globalData, propertyName, attributes, getJSFunction(value));
+ if (currentCapacity != structure()->propertyStorageCapacity())
+ allocatePropertyStorage(globalData, currentCapacity, structure()->propertyStorageCapacity());
+ putDirectOffset(globalData, offset, value);
+}
+
+inline void JSObject::transitionTo(JSGlobalData& globalData, Structure* newStructure)
+{
+ if (structure()->propertyStorageCapacity() != newStructure->propertyStorageCapacity())
+ allocatePropertyStorage(globalData, structure()->propertyStorageCapacity(), newStructure->propertyStorageCapacity());
+ setStructure(globalData, newStructure);
+}
+
+inline JSValue JSObject::toPrimitive(ExecState* exec, PreferredPrimitiveType preferredType) const
+{
+ return methodTable()->defaultValue(this, exec, preferredType);
+}
+
+inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName) const
+{
+ PropertySlot slot(asValue());
+ return get(exec, propertyName, slot);
+}
+
+inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) const
+{
+ if (UNLIKELY(!isCell())) {
+ JSObject* prototype = synthesizePrototype(exec);
+ if (propertyName == exec->propertyNames().underscoreProto)
+ return prototype;
+ if (!prototype->getPropertySlot(exec, propertyName, slot))
+ return jsUndefined();
+ return slot.getValue(exec, propertyName);
+ }
+ JSCell* cell = asCell();
+ while (true) {
+ if (cell->fastGetOwnPropertySlot(exec, propertyName, slot))
+ return slot.getValue(exec, propertyName);
+ JSValue prototype = asObject(cell)->prototype();
+ if (!prototype.isObject())
+ return jsUndefined();
+ cell = asObject(prototype);
+ }
+}
+
+inline JSValue JSValue::get(ExecState* exec, unsigned propertyName) const
+{
+ PropertySlot slot(asValue());
+ return get(exec, propertyName, slot);
+}
+
+inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot& slot) const
+{
+ if (UNLIKELY(!isCell())) {
+ JSObject* prototype = synthesizePrototype(exec);
+ if (!prototype->getPropertySlot(exec, propertyName, slot))
+ return jsUndefined();
+ return slot.getValue(exec, propertyName);
+ }
+ JSCell* cell = const_cast<JSCell*>(asCell());
+ while (true) {
+ if (cell->methodTable()->getOwnPropertySlotByIndex(cell, exec, propertyName, slot))
+ return slot.getValue(exec, propertyName);
+ JSValue prototype = asObject(cell)->prototype();
+ if (!prototype.isObject())
+ return jsUndefined();
+ cell = prototype.asCell();
+ }
+}
+
+inline void JSValue::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ if (UNLIKELY(!isCell())) {
+ JSObject* thisObject = synthesizeObject(exec);
+ thisObject->methodTable()->put(thisObject, exec, propertyName, value, slot);
+ return;
+ }
+ asCell()->methodTable()->put(asCell(), exec, propertyName, value, slot);
+}
+
+inline void JSValue::putDirect(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ ASSERT(isCell() && isObject());
+ if (!asObject(asCell())->putDirect(exec->globalData(), propertyName, value, slot) && slot.isStrictMode())
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+}
+
+inline void JSValue::put(ExecState* exec, unsigned propertyName, JSValue value)
+{
+ if (UNLIKELY(!isCell())) {
+ JSObject* thisObject = synthesizeObject(exec);
+ thisObject->methodTable()->putByIndex(thisObject, exec, propertyName, value);
+ return;
+ }
+ asCell()->methodTable()->putByIndex(asCell(), exec, propertyName, value);
+}
+
+// --- JSValue inlines ----------------------------
+
+ALWAYS_INLINE JSObject* Register::function() const
+{
+ if (!jsValue())
+ return 0;
+ return asObject(jsValue());
+}
+
+ALWAYS_INLINE Register Register::withCallee(JSObject* callee)
+{
+ Register r;
+ r = JSValue(callee);
+ return r;
+}
+
+} // namespace JSC
+
+#endif // JSObject_h
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
new file mode 100644
index 000000000..6fd8b770b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.cpp
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSPropertyNameIterator.h"
+
+#include "JSGlobalObject.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator);
+
+const ClassInfo JSPropertyNameIterator::s_info = { "JSPropertyNameIterator", 0, 0, 0, CREATE_METHOD_TABLE(JSPropertyNameIterator) };
+
+inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots)
+ : JSCell(exec->globalData(), exec->globalData().propertyNameIteratorStructure.get())
+ , m_numCacheableSlots(numCacheableSlots)
+ , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size())
+ , m_jsStrings(adoptArrayPtr(new WriteBarrier<Unknown>[m_jsStringsSize]))
+{
+}
+
+JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o)
+{
+ ASSERT(!o->structure()->enumerationCache() ||
+ o->structure()->enumerationCache()->cachedStructure() != o->structure() ||
+ o->structure()->enumerationCache()->cachedPrototypeChain() != o->structure()->prototypeChain(exec));
+
+ PropertyNameArray propertyNames(exec);
+ o->methodTable()->getPropertyNames(o, exec, propertyNames, ExcludeDontEnumProperties);
+ size_t numCacheableSlots = 0;
+ if (!o->structure()->hasNonEnumerableProperties() && !o->structure()->hasGetterSetterProperties()
+ && !o->structure()->isUncacheableDictionary() && !o->structure()->typeInfo().overridesGetPropertyNames())
+ numCacheableSlots = o->structure()->propertyStorageSize();
+
+ JSPropertyNameIterator* jsPropertyNameIterator = new (NotNull, allocateCell<JSPropertyNameIterator>(*exec->heap())) JSPropertyNameIterator(exec, propertyNames.data(), numCacheableSlots);
+ jsPropertyNameIterator->finishCreation(exec, propertyNames.data());
+
+ if (o->structure()->isDictionary())
+ return jsPropertyNameIterator;
+
+ if (o->structure()->typeInfo().overridesGetPropertyNames())
+ return jsPropertyNameIterator;
+
+ size_t count = normalizePrototypeChain(exec, o);
+ StructureChain* structureChain = o->structure()->prototypeChain(exec);
+ WriteBarrier<Structure>* structure = structureChain->head();
+ for (size_t i = 0; i < count; ++i) {
+ if (structure[i]->typeInfo().overridesGetPropertyNames())
+ return jsPropertyNameIterator;
+ }
+
+ jsPropertyNameIterator->setCachedPrototypeChain(exec->globalData(), structureChain);
+ jsPropertyNameIterator->setCachedStructure(exec->globalData(), o->structure());
+ o->structure()->setEnumerationCache(exec->globalData(), jsPropertyNameIterator);
+ return jsPropertyNameIterator;
+}
+
+void JSPropertyNameIterator::destroy(JSCell* cell)
+{
+ jsCast<JSPropertyNameIterator*>(cell)->JSPropertyNameIterator::~JSPropertyNameIterator();
+}
+
+JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i)
+{
+ JSValue identifier = m_jsStrings[i].get();
+ if (m_cachedStructure.get() == base->structure() && m_cachedPrototypeChain.get() == base->structure()->prototypeChain(exec))
+ return identifier;
+
+ if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value(exec))))
+ return JSValue();
+ return identifier;
+}
+
+void JSPropertyNameIterator::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSPropertyNameIterator* thisObject = jsCast<JSPropertyNameIterator*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ visitor.appendValues(thisObject->m_jsStrings.get(), thisObject->m_jsStringsSize);
+ if (thisObject->m_cachedPrototypeChain)
+ visitor.append(&thisObject->m_cachedPrototypeChain);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
new file mode 100644
index 000000000..d52e3ea61
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSPropertyNameIterator.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSPropertyNameIterator_h
+#define JSPropertyNameIterator_h
+
+#include "JSObject.h"
+#include "JSString.h"
+#include "Operations.h"
+#include "PropertyNameArray.h"
+
+namespace JSC {
+
+ class Identifier;
+ class JSObject;
+
+ class JSPropertyNameIterator : public JSCell {
+ friend class JIT;
+
+ public:
+ typedef JSCell Base;
+
+ static JSPropertyNameIterator* create(ExecState*, JSObject*);
+ static JSPropertyNameIterator* create(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot)
+ {
+ JSPropertyNameIterator* iterator = new (NotNull, allocateCell<JSPropertyNameIterator>(*exec->heap())) JSPropertyNameIterator(exec, propertyNameArrayData, numCacheableSlot);
+ iterator->finishCreation(exec, propertyNameArrayData);
+ return iterator;
+ }
+
+ static void destroy(JSCell*);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info);
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ bool getOffset(size_t i, int& offset)
+ {
+ if (i >= m_numCacheableSlots)
+ return false;
+ offset = i;
+ return true;
+ }
+
+ JSValue get(ExecState*, JSObject*, size_t i);
+ size_t size() { return m_jsStringsSize; }
+
+ void setCachedStructure(JSGlobalData& globalData, Structure* structure)
+ {
+ ASSERT(!m_cachedStructure);
+ ASSERT(structure);
+ m_cachedStructure.set(globalData, this, structure);
+ }
+ Structure* cachedStructure() { return m_cachedStructure.get(); }
+
+ void setCachedPrototypeChain(JSGlobalData& globalData, StructureChain* cachedPrototypeChain) { m_cachedPrototypeChain.set(globalData, this, cachedPrototypeChain); }
+ StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); }
+
+ static const ClassInfo s_info;
+
+ protected:
+ void finishCreation(ExecState* exec, PropertyNameArrayData* propertyNameArrayData)
+ {
+ Base::finishCreation(exec->globalData());
+ PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector();
+ for (size_t i = 0; i < m_jsStringsSize; ++i)
+ m_jsStrings[i].set(exec->globalData(), this, jsOwnedString(exec, propertyNameVector[i].ustring()));
+ }
+
+ private:
+ JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot);
+
+ WriteBarrier<Structure> m_cachedStructure;
+ WriteBarrier<StructureChain> m_cachedPrototypeChain;
+ uint32_t m_numCacheableSlots;
+ uint32_t m_jsStringsSize;
+ OwnArrayPtr<WriteBarrier<Unknown> > m_jsStrings;
+ };
+
+ inline void Structure::setEnumerationCache(JSGlobalData& globalData, JSPropertyNameIterator* enumerationCache)
+ {
+ ASSERT(!isDictionary());
+ m_enumerationCache.set(globalData, this, enumerationCache);
+ }
+
+ inline JSPropertyNameIterator* Structure::enumerationCache()
+ {
+ return m_enumerationCache.get();
+ }
+
+ ALWAYS_INLINE JSPropertyNameIterator* Register::propertyNameIterator() const
+ {
+ return static_cast<JSPropertyNameIterator*>(jsValue().asCell());
+ }
+
+} // namespace JSC
+
+#endif // JSPropertyNameIterator_h
diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp
new file mode 100644
index 000000000..ada921d0e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.cpp
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#include "JSStaticScopeObject.h"
+
+#include "Error.h"
+
+namespace JSC {
+ASSERT_CLASS_FITS_IN_CELL(JSStaticScopeObject);
+
+const ClassInfo JSStaticScopeObject::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(JSStaticScopeObject) };
+
+void JSStaticScopeObject::destroy(JSCell* cell)
+{
+ jsCast<JSStaticScopeObject*>(cell)->JSStaticScopeObject::~JSStaticScopeObject();
+}
+
+void JSStaticScopeObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSStaticScopeObject* thisObject = jsCast<JSStaticScopeObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ JSVariableObject::visitChildren(thisObject, visitor);
+ visitor.append(&thisObject->m_registerStore);
+}
+
+JSObject* JSStaticScopeObject::toThisObject(JSCell*, ExecState* exec)
+{
+ return exec->globalThisValue();
+}
+
+void JSStaticScopeObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ JSStaticScopeObject* thisObject = jsCast<JSStaticScopeObject*>(cell);
+ if (slot.isStrictMode()) {
+ // Double lookup in strict mode, but this only occurs when
+ // a) indirectly writing to an exception slot
+ // b) writing to a function expression name
+ // (a) is unlikely, and (b) is an error.
+ // Also with a single entry the symbol table lookup should simply be
+ // a pointer compare.
+ PropertySlot slot;
+ bool isWritable = true;
+ thisObject->symbolTableGet(propertyName, slot, isWritable);
+ if (!isWritable) {
+ throwError(exec, createTypeError(exec, StrictModeReadonlyPropertyWriteError));
+ return;
+ }
+ }
+ if (thisObject->symbolTablePut(exec, propertyName, value, slot.isStrictMode()))
+ return;
+
+ ASSERT_NOT_REACHED();
+}
+
+void JSStaticScopeObject::putWithAttributes(JSObject* object, ExecState* exec, const Identifier& propertyName, JSValue value, unsigned attributes)
+{
+ JSStaticScopeObject* thisObject = jsCast<JSStaticScopeObject*>(object);
+ if (thisObject->symbolTablePutWithAttributes(exec->globalData(), propertyName, value, attributes))
+ return;
+
+ ASSERT_NOT_REACHED();
+}
+
+bool JSStaticScopeObject::getOwnPropertySlot(JSCell* cell, ExecState*, const Identifier& propertyName, PropertySlot& slot)
+{
+ return jsCast<JSStaticScopeObject*>(cell)->symbolTableGet(propertyName, slot);
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/JSStaticScopeObject.h b/Source/JavaScriptCore/runtime/JSStaticScopeObject.h
new file mode 100644
index 000000000..6a2e51a15
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSStaticScopeObject.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSStaticScopeObject_h
+#define JSStaticScopeObject_h
+
+#include "JSVariableObject.h"
+
+namespace JSC{
+
+ class JSStaticScopeObject : public JSVariableObject {
+ public:
+ typedef JSVariableObject Base;
+
+ static JSStaticScopeObject* create(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes)
+ {
+ JSStaticScopeObject* scopeObject = new (NotNull, allocateCell<JSStaticScopeObject>(*exec->heap())) JSStaticScopeObject(exec);
+ scopeObject->finishCreation(exec, identifier, value, attributes);
+ return scopeObject;
+ }
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+ bool isDynamicScope(bool& requiresDynamicChecks) const;
+ static JSObject* toThisObject(JSCell*, ExecState*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&);
+
+ static void putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned attributes);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(StaticScopeObjectType, StructureFlags), &s_info); }
+
+ static const ClassInfo s_info;
+
+ protected:
+ void finishCreation(ExecState* exec, const Identifier& identifier, JSValue value, unsigned attributes)
+ {
+ Base::finishCreation(exec->globalData());
+ m_registerStore.set(exec->globalData(), this, value);
+ symbolTable().add(identifier.impl(), SymbolTableEntry(-1, attributes));
+ }
+ static const unsigned StructureFlags = IsEnvironmentRecord | OverridesGetOwnPropertySlot | OverridesVisitChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags;
+
+ private:
+ JSStaticScopeObject(ExecState* exec)
+ : JSVariableObject(exec->globalData(), exec->globalData().staticScopeStructure.get(), &m_symbolTable, reinterpret_cast<Register*>(&m_registerStore + 1))
+ {
+ }
+
+ static void destroy(JSCell*);
+
+ SymbolTable m_symbolTable;
+ WriteBarrier<Unknown> m_registerStore;
+ };
+
+ inline bool JSStaticScopeObject::isDynamicScope(bool&) const
+ {
+ return false;
+ }
+
+}
+
+#endif // JSStaticScopeObject_h
diff --git a/Source/JavaScriptCore/runtime/JSString.cpp b/Source/JavaScriptCore/runtime/JSString.cpp
new file mode 100644
index 000000000..93193b5e5
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSString.cpp
@@ -0,0 +1,303 @@
+/*
+ * 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 "JSGlobalObjectFunctions.h"
+#include "JSObject.h"
+#include "Operations.h"
+#include "StringObject.h"
+#include "StringPrototype.h"
+
+namespace JSC {
+
+static const unsigned substringFromRopeCutoff = 4;
+
+const ClassInfo JSString::s_info = { "string", 0, 0, 0, CREATE_METHOD_TABLE(JSString) };
+
+void JSString::RopeBuilder::expand()
+{
+ ASSERT(m_index == JSString::s_maxInternalRopeLength);
+ JSString* jsString = m_jsString;
+ m_jsString = jsStringBuilder(&m_globalData);
+ m_index = 0;
+ append(jsString);
+}
+
+void JSString::destroy(JSCell* cell)
+{
+ JSString* thisObject = jsCast<JSString*>(cell);
+ thisObject->JSString::~JSString();
+}
+
+void JSString::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSString* thisObject = jsCast<JSString*>(cell);
+ Base::visitChildren(thisObject, visitor);
+ for (size_t i = 0; i < s_maxInternalRopeLength && thisObject->m_fibers[i]; ++i)
+ visitor.append(&thisObject->m_fibers[i]);
+}
+
+void JSString::resolveRope(ExecState* exec) const
+{
+ ASSERT(isRope());
+
+ if (is8Bit()) {
+ LChar* buffer;
+ if (RefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer))
+ m_value = newImpl.release();
+ else {
+ outOfMemory(exec);
+ return;
+ }
+
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
+ if (m_fibers[i]->isRope())
+ return resolveRopeSlowCase8(buffer);
+ }
+
+ LChar* position = buffer;
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
+ StringImpl* string = m_fibers[i]->m_value.impl();
+ unsigned length = string->length();
+ StringImpl::copyChars(position, string->characters8(), length);
+ position += length;
+ m_fibers[i].clear();
+ }
+ ASSERT((buffer + m_length) == position);
+ ASSERT(!isRope());
+
+ return;
+ }
+
+ UChar* buffer;
+ if (RefPtr<StringImpl> newImpl = StringImpl::tryCreateUninitialized(m_length, buffer))
+ m_value = newImpl.release();
+ else {
+ outOfMemory(exec);
+ return;
+ }
+
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
+ if (m_fibers[i]->isRope())
+ return resolveRopeSlowCase(buffer);
+ }
+
+ UChar* position = buffer;
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
+ StringImpl* string = m_fibers[i]->m_value.impl();
+ unsigned length = string->length();
+ StringImpl::copyChars(position, string->characters(), length);
+ position += length;
+ m_fibers[i].clear();
+ }
+ ASSERT((buffer + m_length) == position);
+ ASSERT(!isRope());
+}
+
+// Overview: These functions convert a JSString from holding a string in rope form
+// down to a simple UString representation. It does so by building up the string
+// backwards, since we want to avoid recursion, we expect that the tree structure
+// representing the rope is likely imbalanced with more nodes down the left side
+// (since appending to the string is likely more common) - and as such resolving
+// in this fashion should minimize work queue size. (If we built the queue forwards
+// we would likely have to place all of the constituent StringImpls into the
+// Vector before performing any concatenation, but by working backwards we likely
+// only fill the queue with the number of substrings at any given level in a
+// rope-of-ropes.)
+void JSString::resolveRopeSlowCase8(LChar* buffer) const
+{
+ LChar* position = buffer + m_length; // We will be working backwards over the rope.
+ Vector<JSString*, 32> workQueue; // Putting strings into a Vector is only OK because there are no GC points in this method.
+
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i) {
+ workQueue.append(m_fibers[i].get());
+ // Clearing here works only because there are no GC points in this method.
+ m_fibers[i].clear();
+ }
+
+ while (!workQueue.isEmpty()) {
+ JSString* currentFiber = workQueue.last();
+ workQueue.removeLast();
+
+ if (currentFiber->isRope()) {
+ for (size_t i = 0; i < s_maxInternalRopeLength && currentFiber->m_fibers[i]; ++i)
+ workQueue.append(currentFiber->m_fibers[i].get());
+ continue;
+ }
+
+ StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl());
+ unsigned length = string->length();
+ position -= length;
+ StringImpl::copyChars(position, string->characters8(), length);
+ }
+
+ ASSERT(buffer == position);
+ ASSERT(!isRope());
+}
+
+void JSString::resolveRopeSlowCase(UChar* buffer) const
+{
+ UChar* position = buffer + m_length; // We will be working backwards over the rope.
+ Vector<JSString*, 32> workQueue; // These strings are kept alive by the parent rope, so using a Vector is OK.
+
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
+ workQueue.append(m_fibers[i].get());
+
+ while (!workQueue.isEmpty()) {
+ JSString* currentFiber = workQueue.last();
+ workQueue.removeLast();
+
+ if (currentFiber->isRope()) {
+ for (size_t i = 0; i < s_maxInternalRopeLength && currentFiber->m_fibers[i]; ++i)
+ workQueue.append(currentFiber->m_fibers[i].get());
+ continue;
+ }
+
+ StringImpl* string = static_cast<StringImpl*>(currentFiber->m_value.impl());
+ unsigned length = string->length();
+ position -= length;
+ StringImpl::copyChars(position, string->characters(), length);
+ }
+
+ ASSERT(buffer == position);
+ ASSERT(!isRope());
+}
+
+void JSString::outOfMemory(ExecState* exec) const
+{
+ for (size_t i = 0; i < s_maxInternalRopeLength && m_fibers[i]; ++i)
+ m_fibers[i].clear();
+ ASSERT(!isRope());
+ ASSERT(m_value == UString());
+ if (exec)
+ throwOutOfMemoryError(exec);
+}
+
+JSString* JSString::getIndexSlowCase(ExecState* exec, unsigned i)
+{
+ ASSERT(isRope());
+ resolveRope(exec);
+ // Return a safe no-value result, this should never be used, since the excetion will be thrown.
+ if (exec->exception())
+ return jsString(exec, "");
+ ASSERT(!isRope());
+ ASSERT(i < m_value.length());
+ return jsSingleCharacterSubstring(exec, m_value, i);
+}
+
+JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const
+{
+ return const_cast<JSString*>(this);
+}
+
+bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) const
+{
+ result = this;
+ number = jsToNumber(value(exec));
+ return false;
+}
+
+bool JSString::toBoolean(ExecState*) const
+{
+ return m_length;
+}
+
+double JSString::toNumber(ExecState* exec) const
+{
+ return jsToNumber(value(exec));
+}
+
+UString JSString::toString(ExecState* exec) const
+{
+ return value(exec);
+}
+
+inline StringObject* StringObject::create(ExecState* exec, JSGlobalObject* globalObject, JSString* string)
+{
+ StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->globalData(), globalObject->stringObjectStructure());
+ object->finishCreation(exec->globalData(), string);
+ return object;
+}
+
+JSObject* JSString::toObject(ExecState* exec, JSGlobalObject* globalObject) const
+{
+ return StringObject::create(exec, globalObject, const_cast<JSString*>(this));
+}
+
+JSObject* JSString::toThisObject(JSCell* cell, ExecState* exec)
+{
+ return StringObject::create(exec, exec->lexicalGlobalObject(), jsCast<JSString*>(cell));
+}
+
+bool JSString::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ JSString* thisObject = jsCast<JSString*>(cell);
+ // The semantics here are really getPropertySlot, not getOwnPropertySlot.
+ // This function should only be called by JSValue::get.
+ if (thisObject->getStringPropertySlot(exec, propertyName, slot))
+ return true;
+ if (propertyName == exec->propertyNames().underscoreProto) {
+ slot.setValue(exec->lexicalGlobalObject()->stringPrototype());
+ return true;
+ }
+ slot.setBase(thisObject);
+ JSObject* object;
+ for (JSValue prototype = exec->lexicalGlobalObject()->stringPrototype(); !prototype.isNull(); prototype = object->prototype()) {
+ object = asObject(prototype);
+ if (object->methodTable()->getOwnPropertySlot(object, exec, propertyName, slot))
+ return true;
+ }
+ slot.setUndefined();
+ return true;
+}
+
+bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ if (propertyName == exec->propertyNames().length) {
+ descriptor.setDescriptor(jsNumber(m_length), DontEnum | DontDelete | ReadOnly);
+ return true;
+ }
+
+ bool isStrictUInt32;
+ unsigned i = propertyName.toUInt32(isStrictUInt32);
+ if (isStrictUInt32 && i < m_length) {
+ descriptor.setDescriptor(getIndex(exec, i), DontDelete | ReadOnly);
+ return true;
+ }
+
+ return false;
+}
+
+bool JSString::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ JSString* thisObject = jsCast<JSString*>(cell);
+ // The semantics here are really getPropertySlot, not getOwnPropertySlot.
+ // This function should only be called by JSValue::get.
+ if (thisObject->getStringPropertySlot(exec, propertyName, slot))
+ return true;
+ return JSString::getOwnPropertySlot(thisObject, exec, Identifier::from(exec, propertyName), slot);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSString.h b/Source/JavaScriptCore/runtime/JSString.h
new file mode 100644
index 000000000..6700e2e41
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSString.h
@@ -0,0 +1,478 @@
+/*
+ * 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 "CallFrame.h"
+#include "CommonIdentifiers.h"
+#include "Identifier.h"
+#include "PropertyDescriptor.h"
+#include "PropertySlot.h"
+#include "Structure.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(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&);
+
+ JSString* jsStringBuilder(JSGlobalData*);
+
+ class JS_EXPORTCLASS JSString : public JSCell {
+ public:
+ friend class JIT;
+ friend class JSGlobalData;
+ friend class SpecializedThunkJIT;
+ friend struct ThunkHelpers;
+ friend JSString* jsStringBuilder(JSGlobalData*);
+
+ typedef JSCell Base;
+
+ static void destroy(JSCell*);
+
+ class RopeBuilder {
+ public:
+ RopeBuilder(JSGlobalData& globalData)
+ : m_globalData(globalData)
+ , m_jsString(jsStringBuilder(&globalData))
+ , m_index(0)
+ {
+ }
+
+ void append(JSString* jsString)
+ {
+ if (m_index == JSString::s_maxInternalRopeLength)
+ expand();
+ m_jsString->m_fibers[m_index++].set(m_globalData, m_jsString, jsString);
+ m_jsString->m_length += jsString->m_length;
+ m_jsString->m_is8Bit = m_jsString->m_is8Bit && jsString->m_is8Bit;
+ }
+
+ JSString* release()
+ {
+ JSString* tmp = m_jsString;
+ m_jsString = 0;
+ return tmp;
+ }
+
+ unsigned length() { return m_jsString->m_length; }
+
+ private:
+ void expand();
+
+ JSGlobalData& m_globalData;
+ JSString* m_jsString;
+ size_t m_index;
+ };
+
+ private:
+ JSString(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
+ : JSCell(globalData, globalData.stringStructure.get())
+ , m_value(value)
+ {
+ }
+
+ JSString(JSGlobalData& globalData)
+ : JSCell(globalData, globalData.stringStructure.get())
+ {
+ }
+
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData);
+ m_length = 0;
+ m_is8Bit = true;
+ }
+
+ void finishCreation(JSGlobalData& globalData, size_t length)
+ {
+ ASSERT(!m_value.isNull());
+ Base::finishCreation(globalData);
+ m_length = length;
+ m_is8Bit = m_value.impl()->is8Bit();
+ }
+
+ void finishCreation(JSGlobalData& globalData, size_t length, size_t cost)
+ {
+ ASSERT(!m_value.isNull());
+ Base::finishCreation(globalData);
+ m_length = length;
+ m_is8Bit = m_value.impl()->is8Bit();
+ Heap::heap(this)->reportExtraMemoryCost(cost);
+ }
+
+ void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2)
+ {
+ Base::finishCreation(globalData);
+ m_length = s1->length() + s2->length();
+ m_is8Bit = (s1->is8Bit() && s2->is8Bit());
+ m_fibers[0].set(globalData, this, s1);
+ m_fibers[1].set(globalData, this, s2);
+ }
+
+ void finishCreation(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
+ {
+ Base::finishCreation(globalData);
+ m_length = s1->length() + s2->length() + s3->length();
+ m_is8Bit = (s1->is8Bit() && s2->is8Bit() && s3->is8Bit());
+ m_fibers[0].set(globalData, this, s1);
+ m_fibers[1].set(globalData, this, s2);
+ m_fibers[2].set(globalData, this, s3);
+ }
+
+ static JSString* createNull(JSGlobalData& globalData)
+ {
+ JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData);
+ newString->finishCreation(globalData);
+ return newString;
+ }
+
+ public:
+ static JSString* create(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
+ {
+ ASSERT(value);
+ size_t length = value->length();
+ size_t cost = value->cost();
+ JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData, value);
+ newString->finishCreation(globalData, length, cost);
+ return newString;
+ }
+ static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2)
+ {
+ JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData);
+ newString->finishCreation(globalData, s1, s2);
+ return newString;
+ }
+ static JSString* create(JSGlobalData& globalData, JSString* s1, JSString* s2, JSString* s3)
+ {
+ JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData);
+ newString->finishCreation(globalData, s1, s2, s3);
+ return newString;
+ }
+ static JSString* createHasOtherOwner(JSGlobalData& globalData, PassRefPtr<StringImpl> value)
+ {
+ ASSERT(value);
+ size_t length = value->length();
+ JSString* newString = new (NotNull, allocateCell<JSString>(globalData.heap)) JSString(globalData, value);
+ newString->finishCreation(globalData, length);
+ return newString;
+ }
+
+ const UString& value(ExecState* exec) const
+ {
+ if (isRope())
+ resolveRope(exec);
+ return m_value;
+ }
+ const UString& tryGetValue() const
+ {
+ if (isRope())
+ resolveRope(0);
+ return m_value;
+ }
+ unsigned length() { return m_length; }
+
+ JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const;
+ bool toBoolean(ExecState*) const;
+ bool getPrimitiveNumber(ExecState*, double& number, JSValue&) const;
+ JSObject* toObject(ExecState*, JSGlobalObject*) const;
+ UString toString(ExecState*) const;
+ double toNumber(ExecState*) const;
+
+ bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
+ bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
+ bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&);
+
+ bool canGetIndex(unsigned i) { return i < m_length; }
+ JSString* getIndex(ExecState*, unsigned);
+ JSString* getIndexSlowCase(ExecState*, unsigned);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(globalData, globalObject, proto, TypeInfo(StringType, OverridesGetOwnPropertySlot), &s_info);
+ }
+
+ static size_t offsetOfLength() { return OBJECT_OFFSETOF(JSString, m_length); }
+ static size_t offsetOfValue() { return OBJECT_OFFSETOF(JSString, m_value); }
+
+ static const ClassInfo s_info;
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ private:
+ void resolveRope(ExecState*) const;
+ void resolveRopeSlowCase8(LChar*) const;
+ void resolveRopeSlowCase(UChar*) const;
+ void outOfMemory(ExecState*) const;
+
+ static JSObject* toThisObject(JSCell*, ExecState*);
+
+ // Actually getPropertySlot, not getOwnPropertySlot (see JSCell).
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+
+ static const unsigned s_maxInternalRopeLength = 3;
+
+ // A string is represented either by a UString or a rope of fibers.
+ bool m_is8Bit : 1;
+ unsigned m_length;
+ mutable UString m_value;
+ mutable FixedArray<WriteBarrier<JSString>, s_maxInternalRopeLength> m_fibers;
+
+ bool isRope() const { return m_value.isNull(); }
+ bool is8Bit() const { return m_is8Bit; }
+ UString& string() { ASSERT(!isRope()); return m_value; }
+
+ friend JSValue jsString(ExecState*, JSString*, JSString*);
+ friend JSValue jsString(ExecState*, Register*, unsigned count);
+ friend JSValue jsStringFromArguments(ExecState*, JSValue thisValue);
+ friend JSString* jsSubstring(ExecState*, JSString*, unsigned offset, unsigned length);
+ };
+
+ JSString* asString(JSValue);
+
+ inline JSString* asString(JSValue value)
+ {
+ ASSERT(value.asCell()->isString());
+ return static_cast<JSString*>(value.asCell());
+ }
+
+ inline JSString* jsEmptyString(JSGlobalData* globalData)
+ {
+ return globalData->smallStrings.emptyString(globalData);
+ }
+
+ inline JSString* jsSingleCharacterString(JSGlobalData* globalData, UChar c)
+ {
+ if (c <= maxSingleCharacterString)
+ return globalData->smallStrings.singleCharacterString(globalData, c);
+ return JSString::create(*globalData, UString(&c, 1).impl());
+ }
+
+ inline JSString* jsSingleCharacterSubstring(ExecState* exec, const UString& s, unsigned offset)
+ {
+ JSGlobalData* globalData = &exec->globalData();
+ ASSERT(offset < static_cast<unsigned>(s.length()));
+ UChar c = s[offset];
+ if (c <= maxSingleCharacterString)
+ return globalData->smallStrings.singleCharacterString(globalData, c);
+ return JSString::create(*globalData, StringImpl::create(s.impl(), offset, 1));
+ }
+
+ inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s)
+ {
+ ASSERT(s);
+ ASSERT(s[0]);
+ ASSERT(s[1]);
+ return JSString::create(*globalData, UString(s).impl());
+ }
+
+ inline JSString* jsNontrivialString(JSGlobalData* globalData, const UString& s)
+ {
+ ASSERT(s.length() > 1);
+ return JSString::create(*globalData, s.impl());
+ }
+
+ inline JSString* JSString::getIndex(ExecState* exec, unsigned i)
+ {
+ ASSERT(canGetIndex(i));
+ if (isRope())
+ return getIndexSlowCase(exec, i);
+ ASSERT(i < m_value.length());
+ return jsSingleCharacterSubstring(exec, m_value, i);
+ }
+
+ inline JSString* jsString(JSGlobalData* globalData, const UString& s)
+ {
+ int size = s.length();
+ if (!size)
+ return globalData->smallStrings.emptyString(globalData);
+ if (size == 1) {
+ UChar c = s[0];
+ if (c <= maxSingleCharacterString)
+ return globalData->smallStrings.singleCharacterString(globalData, c);
+ }
+ return JSString::create(*globalData, s.impl());
+ }
+
+ inline JSString* jsSubstring(ExecState* exec, JSString* s, unsigned offset, unsigned length)
+ {
+ ASSERT(offset <= static_cast<unsigned>(s->length()));
+ ASSERT(length <= static_cast<unsigned>(s->length()));
+ ASSERT(offset + length <= static_cast<unsigned>(s->length()));
+ JSGlobalData* globalData = &exec->globalData();
+ if (!length)
+ return globalData->smallStrings.emptyString(globalData);
+ return jsSubstring(globalData, s->value(exec), offset, length);
+ }
+
+ inline JSString* jsSubstring8(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
+ {
+ ASSERT(offset <= static_cast<unsigned>(s.length()));
+ ASSERT(length <= static_cast<unsigned>(s.length()));
+ ASSERT(offset + length <= static_cast<unsigned>(s.length()));
+ if (!length)
+ return globalData->smallStrings.emptyString(globalData);
+ if (length == 1) {
+ UChar c = s[offset];
+ if (c <= maxSingleCharacterString)
+ return globalData->smallStrings.singleCharacterString(globalData, c);
+ }
+ return JSString::createHasOtherOwner(*globalData, StringImpl::create8(s.impl(), offset, length));
+ }
+
+ inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length)
+ {
+ ASSERT(offset <= static_cast<unsigned>(s.length()));
+ ASSERT(length <= static_cast<unsigned>(s.length()));
+ ASSERT(offset + length <= static_cast<unsigned>(s.length()));
+ if (!length)
+ return globalData->smallStrings.emptyString(globalData);
+ if (length == 1) {
+ UChar c = s[offset];
+ if (c <= maxSingleCharacterString)
+ return globalData->smallStrings.singleCharacterString(globalData, c);
+ }
+ return JSString::createHasOtherOwner(*globalData, StringImpl::create(s.impl(), offset, length));
+ }
+
+ inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s)
+ {
+ int size = s.length();
+ if (!size)
+ return globalData->smallStrings.emptyString(globalData);
+ if (size == 1) {
+ UChar c = s[0];
+ if (c <= maxSingleCharacterString)
+ return globalData->smallStrings.singleCharacterString(globalData, c);
+ }
+ return JSString::createHasOtherOwner(*globalData, s.impl());
+ }
+
+ inline JSString* jsStringBuilder(JSGlobalData* globalData)
+ {
+ return JSString::createNull(*globalData);
+ }
+
+ 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* jsSubstring8(ExecState* exec, const UString& s, unsigned offset, unsigned length) { return jsSubstring8(&exec->globalData(), s, offset, length); }
+ 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(m_length));
+ return true;
+ }
+
+ bool isStrictUInt32;
+ unsigned i = propertyName.toUInt32(isStrictUInt32);
+ if (isStrictUInt32 && i < m_length) {
+ slot.setValue(getIndex(exec, i));
+ return true;
+ }
+
+ return false;
+ }
+
+ ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
+ {
+ if (propertyName < m_length) {
+ slot.setValue(getIndex(exec, propertyName));
+ return true;
+ }
+
+ return false;
+ }
+
+ inline bool isJSString(JSValue v) { return v.isCell() && v.asCell()->classInfo() == &JSString::s_info; }
+
+ inline bool JSCell::toBoolean(ExecState* exec) const
+ {
+ if (isString())
+ return static_cast<const JSString*>(this)->toBoolean(exec);
+ return !structure()->typeInfo().masqueradesAsUndefined();
+ }
+
+ // --- JSValue inlines ----------------------------
+
+ inline bool JSValue::toBoolean(ExecState* exec) const
+ {
+ if (isInt32())
+ return asInt32();
+ if (isDouble())
+ return asDouble() > 0.0 || asDouble() < 0.0; // false for NaN
+ if (isCell())
+ return asCell()->toBoolean(exec);
+ return isTrue(); // false, null, and undefined all convert to false.
+ }
+
+ inline UString JSValue::toString(ExecState* exec) const
+ {
+ if (isString())
+ return static_cast<JSString*>(asCell())->value(exec);
+ if (isInt32())
+ return exec->globalData().numericStrings.add(asInt32());
+ if (isDouble())
+ return exec->globalData().numericStrings.add(asDouble());
+ if (isTrue())
+ return "true";
+ if (isFalse())
+ return "false";
+ if (isNull())
+ return "null";
+ if (isUndefined())
+ return "undefined";
+ ASSERT(isCell());
+ return asCell()->toString(exec);
+ }
+
+} // namespace JSC
+
+#endif // JSString_h
diff --git a/Source/JavaScriptCore/runtime/JSStringBuilder.h b/Source/JavaScriptCore/runtime/JSStringBuilder.h
new file mode 100644
index 000000000..b7e7e781e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSStringBuilder.h
@@ -0,0 +1,194 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSStringBuilder_h
+#define JSStringBuilder_h
+
+#include "ExceptionHelpers.h"
+#include "JSString.h"
+#include "UStringConcatenate.h"
+#include "Vector.h"
+
+namespace JSC {
+
+class JSStringBuilder {
+public:
+ JSStringBuilder()
+ : m_okay(true)
+ , m_is8Bit(true)
+ {
+ }
+
+ void append(const UChar u)
+ {
+ if (m_is8Bit) {
+ if (u < 0xff) {
+ LChar c = u;
+ m_okay &= buffer8.tryAppend(&c, 1);
+ return;
+ }
+ upConvert();
+ }
+ m_okay &= buffer16.tryAppend(&u, 1);
+ }
+
+ void append(const char* str)
+ {
+ append(str, strlen(str));
+ }
+
+ void append(const char* str, size_t len)
+ {
+ if (m_is8Bit) {
+ m_okay &= buffer8.tryAppend(reinterpret_cast<const LChar*>(str), len);
+ return;
+ }
+ m_okay &= buffer8.tryReserveCapacity(buffer16.size() + len);
+ for (size_t i = 0; i < len; i++) {
+ UChar u = static_cast<unsigned char>(str[i]);
+ m_okay &= buffer16.tryAppend(&u, 1);
+ }
+ }
+
+ void append(const LChar* str, size_t len)
+ {
+ if (m_is8Bit) {
+ m_okay &= buffer8.tryAppend(str, len);
+ return;
+ }
+ m_okay &= buffer8.tryReserveCapacity(buffer16.size() + len);
+ for (size_t i = 0; i < len; i++) {
+ UChar u = str[i];
+ m_okay &= buffer16.tryAppend(&u, 1);
+ }
+ }
+
+ void append(const UChar* str, size_t len)
+ {
+ if (m_is8Bit)
+ upConvert(); // FIXME: We could check character by character its size.
+ m_okay &= buffer16.tryAppend(str, len);
+ }
+
+ void append(const UString& str)
+ {
+ unsigned length = str.length();
+
+ if (!length)
+ return;
+
+ if (m_is8Bit) {
+ if (str.is8Bit()) {
+ m_okay &= buffer8.tryAppend(str.characters8(), length);
+ return;
+ }
+ upConvert();
+ }
+ m_okay &= buffer16.tryAppend(str.characters(), length);
+ }
+
+ void upConvert()
+ {
+ ASSERT(m_is8Bit);
+ size_t len = buffer8.size();
+
+ for (size_t i = 0; i < len; i++)
+ buffer16.append(buffer8[i]);
+
+ buffer8.clear();
+ m_is8Bit = false;
+ }
+
+ JSValue build(ExecState* exec)
+ {
+ if (!m_okay)
+ return throwOutOfMemoryError(exec);
+ if (m_is8Bit) {
+ buffer8.shrinkToFit();
+ if (!buffer8.data())
+ return throwOutOfMemoryError(exec);
+ return jsString(exec, UString::adopt(buffer8));
+ }
+ buffer16.shrinkToFit();
+ if (!buffer16.data())
+ return throwOutOfMemoryError(exec);
+ return jsString(exec, UString::adopt(buffer16));
+ }
+
+protected:
+ Vector<LChar, 64> buffer8;
+ Vector<UChar, 64> buffer16;
+ bool m_okay;
+ bool m_is8Bit;
+};
+
+template<typename StringType1, typename StringType2>
+inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2)
+{
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2);
+ if (!result)
+ return throwOutOfMemoryError(exec);
+ return jsNontrivialString(exec, result);
+}
+
+template<typename StringType1, typename StringType2, typename StringType3>
+inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3)
+{
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3);
+ if (!result)
+ return throwOutOfMemoryError(exec);
+ return jsNontrivialString(exec, result);
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
+inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
+{
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4);
+ if (!result)
+ return throwOutOfMemoryError(exec);
+ return jsNontrivialString(exec, result);
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
+inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
+{
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4, string5);
+ if (!result)
+ return throwOutOfMemoryError(exec);
+ return jsNontrivialString(exec, result);
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
+inline JSValue jsMakeNontrivialString(ExecState* exec, StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
+{
+ PassRefPtr<StringImpl> result = WTF::tryMakeString(string1, string2, string3, string4, string5, string6);
+ if (!result)
+ return throwOutOfMemoryError(exec);
+ return jsNontrivialString(exec, result);
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/JSType.h b/Source/JavaScriptCore/runtime/JSType.h
new file mode 100644
index 000000000..84a27a7ea
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSType.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2006, 2007, 2008, 2009, 2010, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef JSType_h
+#define JSType_h
+
+namespace JSC {
+
+enum JSType {
+ UnspecifiedType,
+ UndefinedType,
+ BooleanType,
+ NumberType,
+ NullType,
+ StringType,
+ LeafType,
+
+ // The CompoundType value must come before any JSType that may have children.
+ CompoundType,
+ GetterSetterType,
+ APIValueWrapperType,
+
+ EvalExecutableType,
+ ProgramExecutableType,
+ FunctionExecutableType,
+
+ // The ObjectType value must come before any JSType that is a subclass of JSObject.
+ ObjectType,
+ FinalObjectType,
+ JSFunctionType,
+ NumberObjectType,
+ ErrorInstanceType,
+ GlobalThisType,
+
+ // VariableObjectType must come before all of the types of its subclasses and only its subclasses.
+ VariableObjectType,
+ GlobalObjectType,
+ ActivationObjectType,
+ StaticScopeObjectType,
+};
+
+} // namespace JSC
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/JSTypeInfo.h b/Source/JavaScriptCore/runtime/JSTypeInfo.h
new file mode 100644
index 000000000..3e23aa253
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSTypeInfo.h
@@ -0,0 +1,100 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSTypeInfo_h
+#define JSTypeInfo_h
+
+// This file would be called TypeInfo.h, but that conflicts with <typeinfo.h>
+// in the STL on systems without case-sensitive file systems.
+
+#include "JSType.h"
+
+namespace JSC {
+
+ static const unsigned MasqueradesAsUndefined = 1; // WebCore uses MasqueradesAsUndefined to make document.all undetectable.
+ static const unsigned ImplementsHasInstance = 1 << 1;
+ static const unsigned OverridesHasInstance = 1 << 2;
+ static const unsigned ImplementsDefaultHasInstance = 1 << 3;
+ static const unsigned IsEnvironmentRecord = 1 << 4;
+ static const unsigned OverridesGetOwnPropertySlot = 1 << 5;
+ static const unsigned OverridesVisitChildren = 1 << 6;
+ static const unsigned OverridesGetPropertyNames = 1 << 7;
+ static const unsigned ProhibitsPropertyCaching = 1 << 8;
+
+ class TypeInfo {
+ public:
+ TypeInfo(JSType type, unsigned flags = 0)
+ : m_type(type)
+ , m_flags(flags & 0xff)
+ , m_flags2(flags >> 8)
+ {
+ ASSERT(flags <= 0x3ff);
+ ASSERT(type <= 0xff);
+ ASSERT(type >= CompoundType || !(flags & OverridesVisitChildren));
+ // No object that doesn't ImplementsHasInstance should override it!
+ ASSERT((m_flags & (ImplementsHasInstance | OverridesHasInstance)) != OverridesHasInstance);
+ // ImplementsDefaultHasInstance means (ImplementsHasInstance & !OverridesHasInstance)
+ if ((m_flags & (ImplementsHasInstance | OverridesHasInstance)) == ImplementsHasInstance)
+ m_flags |= ImplementsDefaultHasInstance;
+ }
+
+ JSType type() const { return static_cast<JSType>(m_type); }
+ bool isObject() const { return type() >= ObjectType; }
+ bool isFinalObject() const { return type() == FinalObjectType; }
+ bool isNumberObject() const { return type() == NumberObjectType; }
+
+ bool masqueradesAsUndefined() const { return isSetOnFlags1(MasqueradesAsUndefined); }
+ bool implementsHasInstance() const { return isSetOnFlags1(ImplementsHasInstance); }
+ bool isEnvironmentRecord() const { return isSetOnFlags1(IsEnvironmentRecord); }
+ bool overridesHasInstance() const { return isSetOnFlags1(OverridesHasInstance); }
+ bool implementsDefaultHasInstance() const { return isSetOnFlags1(ImplementsDefaultHasInstance); }
+ bool overridesGetOwnPropertySlot() const { return isSetOnFlags1(OverridesGetOwnPropertySlot); }
+ bool overridesVisitChildren() const { return isSetOnFlags1(OverridesVisitChildren); }
+ bool overridesGetPropertyNames() const { return isSetOnFlags1(OverridesGetPropertyNames); }
+ bool prohibitsPropertyCaching() const { return isSetOnFlags2(ProhibitsPropertyCaching); }
+
+ static ptrdiff_t flagsOffset()
+ {
+ return OBJECT_OFFSETOF(TypeInfo, m_flags);
+ }
+
+ static ptrdiff_t typeOffset()
+ {
+ return OBJECT_OFFSETOF(TypeInfo, m_type);
+ }
+
+ private:
+ bool isSetOnFlags1(unsigned flag) const { ASSERT(flag <= (1 << 7)); return m_flags & flag; }
+ bool isSetOnFlags2(unsigned flag) const { ASSERT(flag >= (1 << 8)); return m_flags2 & (flag >> 8); }
+
+ unsigned char m_type;
+ unsigned char m_flags;
+ unsigned char m_flags2;
+ };
+
+}
+
+#endif // JSTypeInfo_h
diff --git a/Source/JavaScriptCore/runtime/JSValue.cpp b/Source/JavaScriptCore/runtime/JSValue.cpp
new file mode 100644
index 000000000..a5d3d936a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSValue.cpp
@@ -0,0 +1,231 @@
+/*
+ * 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 "BooleanConstructor.h"
+#include "BooleanPrototype.h"
+#include "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSGlobalObject.h"
+#include "JSFunction.h"
+#include "JSNotAnObject.h"
+#include "NumberObject.h"
+#include <wtf/MathExtras.h>
+#include <wtf/StringExtras.h>
+
+namespace JSC {
+
+static const double D32 = 4294967296.0;
+
+// ECMA 9.4
+double JSValue::toInteger(ExecState* exec) const
+{
+ if (isInt32())
+ return asInt32();
+ double d = toNumber(exec);
+ return isnan(d) ? 0.0 : trunc(d);
+}
+
+double JSValue::toIntegerPreserveNaN(ExecState* exec) const
+{
+ if (isInt32())
+ return asInt32();
+ return trunc(toNumber(exec));
+}
+
+double JSValue::toNumberSlowCase(ExecState* exec) const
+{
+ ASSERT(!isInt32() && !isDouble());
+ if (isCell())
+ return asCell()->toNumber(exec);
+ if (isTrue())
+ return 1.0;
+ return isUndefined() ? std::numeric_limits<double>::quiet_NaN() : 0; // null and false both convert to 0.
+}
+
+JSObject* JSValue::toObjectSlowCase(ExecState* exec, JSGlobalObject* globalObject) const
+{
+ ASSERT(!isCell());
+
+ if (isInt32() || isDouble())
+ return constructNumber(exec, globalObject, asValue());
+ if (isTrue() || isFalse())
+ return constructBooleanFromImmediateBoolean(exec, globalObject, asValue());
+
+ ASSERT(isUndefinedOrNull());
+ throwError(exec, createNotAnObjectError(exec, *this));
+ return JSNotAnObject::create(exec);
+}
+
+JSObject* JSValue::toThisObjectSlowCase(ExecState* exec) const
+{
+ ASSERT(!isCell());
+
+ if (isInt32() || isDouble())
+ return constructNumber(exec, exec->lexicalGlobalObject(), asValue());
+ if (isTrue() || isFalse())
+ return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue());
+ ASSERT(isUndefinedOrNull());
+ return exec->globalThisValue();
+}
+
+JSObject* JSValue::synthesizeObject(ExecState* exec) const
+{
+ ASSERT(!isCell());
+ if (isNumber())
+ return constructNumber(exec, exec->lexicalGlobalObject(), asValue());
+ if (isBoolean())
+ return constructBooleanFromImmediateBoolean(exec, exec->lexicalGlobalObject(), asValue());
+
+ ASSERT(isUndefinedOrNull());
+ throwError(exec, createNotAnObjectError(exec, *this));
+ return JSNotAnObject::create(exec);
+}
+
+JSObject* JSValue::synthesizePrototype(ExecState* exec) const
+{
+ ASSERT(!isCell());
+ if (isNumber())
+ return exec->lexicalGlobalObject()->numberPrototype();
+ if (isBoolean())
+ return exec->lexicalGlobalObject()->booleanPrototype();
+
+ ASSERT(isUndefinedOrNull());
+ throwError(exec, createNotAnObjectError(exec, *this));
+ return JSNotAnObject::create(exec);
+}
+
+#ifndef NDEBUG
+char* JSValue::description()
+{
+ static const size_t size = 64;
+ static char description[size];
+
+ if (!*this)
+ snprintf(description, size, "<JSValue()>");
+ else if (isInt32())
+ snprintf(description, size, "Int32: %d", asInt32());
+ else if (isDouble()) {
+#if USE(JSVALUE64)
+ snprintf(description, size, "Double: %lf, %lx", asDouble(), reinterpretDoubleToIntptr(asDouble()));
+#else
+ union {
+ double asDouble;
+ uint32_t asTwoInt32s[2];
+ } u;
+ u.asDouble = asDouble();
+ snprintf(description, size, "Double: %lf, %08x:%08x", asDouble(), u.asTwoInt32s[1], u.asTwoInt32s[0]);
+#endif
+ } else if (isCell())
+ snprintf(description, size, "Cell: %p", asCell());
+ else if (isTrue())
+ snprintf(description, size, "True");
+ else if (isFalse())
+ snprintf(description, size, "False");
+ else if (isNull())
+ snprintf(description, size, "Null");
+ else if (isUndefined())
+ snprintf(description, size, "Undefined");
+ else
+ snprintf(description, size, "INVALID");
+
+ return description;
+}
+#endif
+
+// This in the ToInt32 operation is defined in section 9.5 of the ECMA-262 spec.
+// Note that this operation is identical to ToUInt32 other than to interpretation
+// of the resulting bit-pattern (as such this metod is also called to implement
+// ToUInt32).
+//
+// The operation can be descibed as round towards zero, then select the 32 least
+// bits of the resulting value in 2s-complement representation.
+int32_t toInt32(double number)
+{
+ int64_t bits = WTF::bitwise_cast<int64_t>(number);
+ int32_t exp = (static_cast<int32_t>(bits >> 52) & 0x7ff) - 0x3ff;
+
+ // If exponent < 0 there will be no bits to the left of the decimal point
+ // after rounding; if the exponent is > 83 then no bits of precision can be
+ // left in the low 32-bit range of the result (IEEE-754 doubles have 52 bits
+ // of fractional precision).
+ // Note this case handles 0, -0, and all infinte, NaN, & denormal value.
+ if (exp < 0 || exp > 83)
+ return 0;
+
+ // Select the appropriate 32-bits from the floating point mantissa. If the
+ // exponent is 52 then the bits we need to select are already aligned to the
+ // lowest bits of the 64-bit integer representation of tghe number, no need
+ // to shift. If the exponent is greater than 52 we need to shift the value
+ // left by (exp - 52), if the value is less than 52 we need to shift right
+ // accordingly.
+ int32_t result = (exp > 52)
+ ? static_cast<int32_t>(bits << (exp - 52))
+ : static_cast<int32_t>(bits >> (52 - exp));
+
+ // IEEE-754 double precision values are stored omitting an implicit 1 before
+ // the decimal point; we need to reinsert this now. We may also the shifted
+ // invalid bits into the result that are not a part of the mantissa (the sign
+ // and exponent bits from the floatingpoint representation); mask these out.
+ if (exp < 32) {
+ int32_t missingOne = 1 << exp;
+ result &= missingOne - 1;
+ result += missingOne;
+ }
+
+ // If the input value was negative (we could test either 'number' or 'bits',
+ // but testing 'bits' is likely faster) invert the result appropriately.
+ return bits < 0 ? -result : result;
+}
+
+bool JSValue::isValidCallee()
+{
+ return asObject(asCell())->globalObject();
+}
+
+JSString* JSValue::toPrimitiveString(ExecState* exec) const
+{
+ if (isString())
+ return static_cast<JSString*>(asCell());
+ if (isInt32())
+ return jsString(&exec->globalData(), exec->globalData().numericStrings.add(asInt32()));
+ if (isDouble())
+ return jsString(&exec->globalData(), exec->globalData().numericStrings.add(asDouble()));
+ if (isTrue())
+ return jsNontrivialString(exec, exec->propertyNames().trueKeyword.ustring());
+ if (isFalse())
+ return jsNontrivialString(exec, exec->propertyNames().falseKeyword.ustring());
+ if (isNull())
+ return jsNontrivialString(exec, exec->propertyNames().nullKeyword.ustring());
+ if (isUndefined())
+ return jsNontrivialString(exec, exec->propertyNames().undefined.ustring());
+
+ ASSERT(isCell());
+ JSValue v = asCell()->toPrimitive(exec, NoPreference);
+ if (v.isString())
+ return static_cast<JSString*>(v.asCell());
+ return jsString(&exec->globalData(), v.toString(exec));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSValue.h b/Source/JavaScriptCore/runtime/JSValue.h
new file mode 100644
index 000000000..a00106274
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSValue.h
@@ -0,0 +1,478 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2007, 2008, 2009 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 <math.h>
+#include <stddef.h> // for size_t
+#include <stdint.h>
+#include <wtf/AlwaysInline.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashTraits.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+ class ExecState;
+ class Identifier;
+ class JSCell;
+ class JSGlobalData;
+ class JSGlobalObject;
+ class JSObject;
+ class JSString;
+ class PropertySlot;
+ class PutPropertySlot;
+ class UString;
+#if ENABLE(DFG_JIT)
+ namespace DFG {
+ class AssemblyHelpers;
+ class JITCompiler;
+ class JITCodeGenerator;
+ class JSValueSource;
+ class OSRExitCompiler;
+ class SpeculativeJIT;
+ }
+#endif
+
+ struct ClassInfo;
+ struct Instruction;
+ struct MethodTable;
+
+ template <class T> class WriteBarrierBase;
+
+ enum PreferredPrimitiveType { NoPreference, PreferNumber, PreferString };
+
+
+#if USE(JSVALUE32_64)
+ typedef int64_t EncodedJSValue;
+#else
+ typedef void* EncodedJSValue;
+#endif
+
+ union EncodedValueDescriptor {
+ int64_t asInt64;
+#if USE(JSVALUE32_64)
+ double asDouble;
+#elif USE(JSVALUE64)
+ JSCell* ptr;
+#endif
+
+#if CPU(BIG_ENDIAN)
+ struct {
+ int32_t tag;
+ int32_t payload;
+ } asBits;
+#else
+ struct {
+ int32_t payload;
+ int32_t tag;
+ } asBits;
+#endif
+ };
+
+ // This implements ToInt32, defined in ECMA-262 9.5.
+ int32_t toInt32(double);
+
+ // This implements ToUInt32, defined in ECMA-262 9.6.
+ inline uint32_t toUInt32(double number)
+ {
+ // As commented in the spec, the operation of ToInt32 and ToUint32 only differ
+ // in how the result is interpreted; see NOTEs in sections 9.5 and 9.6.
+ return toInt32(number);
+ }
+
+ class JSValue {
+ friend struct EncodedJSValueHashTraits;
+ friend class JIT;
+ friend class JITStubs;
+ friend class JITStubCall;
+ friend class JSInterfaceJIT;
+ friend class SpecializedThunkJIT;
+#if ENABLE(DFG_JIT)
+ friend class DFG::AssemblyHelpers;
+ friend class DFG::JITCompiler;
+ friend class DFG::JITCodeGenerator;
+ friend class DFG::JSValueSource;
+ friend class DFG::OSRExitCompiler;
+ friend class DFG::SpeculativeJIT;
+#endif
+
+ public:
+ static EncodedJSValue encode(JSValue);
+ static JSValue decode(EncodedJSValue);
+
+ enum JSNullTag { JSNull };
+ enum JSUndefinedTag { JSUndefined };
+ enum JSTrueTag { JSTrue };
+ enum JSFalseTag { JSFalse };
+ enum EncodeAsDoubleTag { EncodeAsDouble };
+
+ JSValue();
+ JSValue(JSNullTag);
+ JSValue(JSUndefinedTag);
+ JSValue(JSTrueTag);
+ JSValue(JSFalseTag);
+ JSValue(JSCell* ptr);
+ JSValue(const JSCell* ptr);
+
+ // Numbers
+ JSValue(EncodeAsDoubleTag, double);
+ explicit JSValue(double);
+ explicit JSValue(char);
+ explicit JSValue(unsigned char);
+ explicit JSValue(short);
+ explicit JSValue(unsigned short);
+ explicit JSValue(int);
+ explicit JSValue(unsigned);
+ explicit JSValue(long);
+ explicit JSValue(unsigned long);
+ explicit JSValue(long long);
+ explicit JSValue(unsigned long long);
+
+ operator bool() const;
+ bool operator==(const JSValue& other) const;
+ bool operator!=(const JSValue& other) const;
+
+ bool isInt32() const;
+ bool isUInt32() const;
+ bool isDouble() const;
+ bool isTrue() const;
+ bool isFalse() const;
+
+ int32_t asInt32() const;
+ uint32_t asUInt32() const;
+ double asDouble() const;
+ bool asBoolean() const;
+ double asNumber() const;
+
+ // Querying the type.
+ bool isEmpty() const;
+ bool isUndefined() const;
+ bool isNull() const;
+ bool isUndefinedOrNull() const;
+ bool isBoolean() const;
+ bool isNumber() const;
+ bool isString() const;
+ bool isPrimitive() const;
+ bool isGetterSetter() const;
+ bool isObject() const;
+ bool inherits(const ClassInfo*) const;
+
+ // Extracting the value.
+ bool getString(ExecState* exec, UString&) const;
+ UString getString(ExecState* exec) const; // null string if not a string
+ JSObject* getObject() const; // 0 if not an object
+
+ // Extracting integer values.
+ bool getUInt32(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;
+ UString toString(ExecState*) const;
+ JSString* toPrimitiveString(ExecState*) const;
+ JSObject* toObject(ExecState*) const;
+ JSObject* toObject(ExecState*, JSGlobalObject*) const;
+
+ // Integer conversions.
+ double toInteger(ExecState*) const;
+ double toIntegerPreserveNaN(ExecState*) const;
+ int32_t toInt32(ExecState*) const;
+ uint32_t toUInt32(ExecState*) const;
+
+ // Floating point conversions (this is a convenience method for webcore;
+ // signle precision float is not a representation used in JS or JSC).
+ float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); }
+
+ // Object operations, with the toObject operation included.
+ 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 putDirect(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+ void put(ExecState*, unsigned propertyName, JSValue);
+
+ JSObject* toThisObject(ExecState*) const;
+
+ static bool equal(ExecState* exec, JSValue v1, JSValue v2);
+ static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2);
+ static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2);
+ static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2);
+ static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2);
+ static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2);
+
+ bool isCell() const;
+ JSCell* asCell() const;
+ bool isValidCallee();
+
+#ifndef NDEBUG
+ char* description();
+#endif
+
+ private:
+ template <class T> JSValue(WriteBarrierBase<T>);
+
+ enum HashTableDeletedValueTag { HashTableDeletedValue };
+ JSValue(HashTableDeletedValueTag);
+
+ inline const JSValue asValue() const { return *this; }
+ double toNumberSlowCase(ExecState*) const;
+ JSObject* toObjectSlowCase(ExecState*, JSGlobalObject*) const;
+ JSObject* toThisObjectSlowCase(ExecState*) const;
+
+ JSObject* synthesizePrototype(ExecState*) const;
+ JSObject* synthesizeObject(ExecState*) const;
+
+#if USE(JSVALUE32_64)
+ /*
+ * On 32-bit platforms USE(JSVALUE32_64) should be defined, and we use a NaN-encoded
+ * form for immediates.
+ *
+ * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
+ * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
+ * can encode a 51-bit payload. Hardware produced and C-library payloads typically
+ * have a payload of zero. We assume that non-zero payloads are available to encode
+ * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
+ * all set represents a NaN with a non-zero payload, we can use this space in the NaN
+ * ranges to encode other values (however there are also other ranges of NaN space that
+ * could have been selected).
+ *
+ * For JSValues that do not contain a double value, the high 32 bits contain the tag
+ * values listed in the enums below, which all correspond to NaN-space. In the case of
+ * cell, integer and bool values the lower 32 bits (the 'payload') contain the pointer
+ * integer or boolean value; in the case of all other tags the payload is 0.
+ */
+ enum { Int32Tag = 0xffffffff };
+ enum { BooleanTag = 0xfffffffe };
+ enum { NullTag = 0xfffffffd };
+ enum { UndefinedTag = 0xfffffffc };
+ enum { CellTag = 0xfffffffb };
+ enum { EmptyValueTag = 0xfffffffa };
+ enum { DeletedValueTag = 0xfffffff9 };
+
+ enum { LowestTag = DeletedValueTag };
+
+ uint32_t tag() const;
+ int32_t payload() const;
+#elif USE(JSVALUE64)
+ /*
+ * On 64-bit platforms USE(JSVALUE64) should be defined, and we use a NaN-encoded
+ * form for immediates.
+ *
+ * The encoding makes use of unused NaN space in the IEEE754 representation. Any value
+ * with the top 13 bits set represents a QNaN (with the sign bit set). QNaN values
+ * can encode a 51-bit payload. Hardware produced and C-library payloads typically
+ * have a payload of zero. We assume that non-zero payloads are available to encode
+ * pointer and integer values. Since any 64-bit bit pattern where the top 15 bits are
+ * all set represents a NaN with a non-zero payload, we can use this space in the NaN
+ * ranges to encode other values (however there are also other ranges of NaN space that
+ * could have been selected).
+ *
+ * This range of NaN space is represented by 64-bit numbers begining with the 16-bit
+ * hex patterns 0xFFFE and 0xFFFF - we rely on the fact that no valid double-precision
+ * numbers will begin fall in these ranges.
+ *
+ * The top 16-bits denote the type of the encoded JSValue:
+ *
+ * Pointer { 0000:PPPP:PPPP:PPPP
+ * / 0001:****:****:****
+ * Double { ...
+ * \ FFFE:****:****:****
+ * Integer { FFFF:0000:IIII:IIII
+ *
+ * The scheme we have implemented encodes double precision values by performing a
+ * 64-bit integer addition of the value 2^48 to the number. After this manipulation
+ * no encoded double-precision value will begin with the pattern 0x0000 or 0xFFFF.
+ * Values must be decoded by reversing this operation before subsequent floating point
+ * operations my be peformed.
+ *
+ * 32-bit signed integers are marked with the 16-bit tag 0xFFFF.
+ *
+ * The tag 0x0000 denotes a pointer, or another form of tagged immediate. Boolean,
+ * null and undefined values are represented by specific, invalid pointer values:
+ *
+ * False: 0x06
+ * True: 0x07
+ * Undefined: 0x0a
+ * Null: 0x02
+ *
+ * These values have the following properties:
+ * - Bit 1 (TagBitTypeOther) is set for all four values, allowing real pointers to be
+ * quickly distinguished from all immediate values, including these invalid pointers.
+ * - With bit 3 is masked out (TagBitUndefined) Undefined and Null share the
+ * same value, allowing null & undefined to be quickly detected.
+ *
+ * No valid JSValue will have the bit pattern 0x0, this is used to represent array
+ * holes, and as a C++ 'no value' result (e.g. JSValue() has an internal value of 0).
+ */
+
+ // These values are #defines since using static const integers here is a ~1% regression!
+
+ // This value is 2^48, used to encode doubles such that the encoded value will begin
+ // with a 16-bit pattern within the range 0x0001..0xFFFE.
+ #define DoubleEncodeOffset 0x1000000000000ll
+ // If all bits in the mask are set, this indicates an integer number,
+ // if any but not all are set this value is a double precision number.
+ #define TagTypeNumber 0xffff000000000000ll
+
+ // All non-numeric (bool, null, undefined) immediates have bit 2 set.
+ #define TagBitTypeOther 0x2ll
+ #define TagBitBool 0x4ll
+ #define TagBitUndefined 0x8ll
+ // Combined integer value for non-numeric immediates.
+ #define ValueFalse (TagBitTypeOther | TagBitBool | false)
+ #define ValueTrue (TagBitTypeOther | TagBitBool | true)
+ #define ValueUndefined (TagBitTypeOther | TagBitUndefined)
+ #define ValueNull (TagBitTypeOther)
+
+ // TagMask is used to check for all types of immediate values (either number or 'other').
+ #define TagMask (TagTypeNumber | TagBitTypeOther)
+
+ // These special values are never visible to JavaScript code; Empty is used to represent
+ // Array holes, and for uninitialized JSValues. Deleted is used in hash table code.
+ // These values would map to cell types in the JSValue encoding, but not valid GC cell
+ // pointer should have either of these values (Empty is null, deleted is at an invalid
+ // alignment for a GC cell, and in the zero page).
+ #define ValueEmpty 0x0ll
+ #define ValueDeleted 0x4ll
+#endif
+
+ EncodedValueDescriptor u;
+ };
+
+#if USE(JSVALUE32_64)
+ typedef IntHash<EncodedJSValue> EncodedJSValueHash;
+
+ struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> {
+ static const bool emptyValueIsZero = false;
+ static EncodedJSValue emptyValue() { return JSValue::encode(JSValue()); }
+ static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
+ static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
+ };
+#else
+ typedef PtrHash<EncodedJSValue> EncodedJSValueHash;
+
+ struct EncodedJSValueHashTraits : HashTraits<EncodedJSValue> {
+ static void constructDeletedValue(EncodedJSValue& slot) { slot = JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
+ static bool isDeletedValue(EncodedJSValue value) { return value == JSValue::encode(JSValue(JSValue::HashTableDeletedValue)); }
+ };
+#endif
+
+ typedef HashMap<EncodedJSValue, unsigned, EncodedJSValueHash, EncodedJSValueHashTraits> JSValueMap;
+
+ // Stand-alone helper functions.
+ inline JSValue jsNull()
+ {
+ return JSValue(JSValue::JSNull);
+ }
+
+ inline JSValue jsUndefined()
+ {
+ return JSValue(JSValue::JSUndefined);
+ }
+
+ inline JSValue jsBoolean(bool b)
+ {
+ return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse);
+ }
+
+ ALWAYS_INLINE JSValue jsDoubleNumber(double d)
+ {
+ ASSERT(JSValue(JSValue::EncodeAsDouble, d).isNumber());
+ return JSValue(JSValue::EncodeAsDouble, d);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(double d)
+ {
+ ASSERT(JSValue(d).isNumber());
+ return JSValue(d);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(char i)
+ {
+ return JSValue(i);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(unsigned char i)
+ {
+ return JSValue(i);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(short i)
+ {
+ return JSValue(i);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(unsigned short i)
+ {
+ return JSValue(i);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(int i)
+ {
+ return JSValue(i);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(unsigned i)
+ {
+ return JSValue(i);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(long i)
+ {
+ return JSValue(i);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(unsigned long i)
+ {
+ return JSValue(i);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(long long i)
+ {
+ return JSValue(i);
+ }
+
+ ALWAYS_INLINE JSValue jsNumber(unsigned long long i)
+ {
+ return JSValue(i);
+ }
+
+ inline bool operator==(const JSValue a, const JSCell* b) { return a == JSValue(b); }
+ inline bool operator==(const JSCell* a, const JSValue b) { return JSValue(a) == b; }
+
+ inline bool operator!=(const JSValue a, const JSCell* b) { return a != JSValue(b); }
+ inline bool operator!=(const JSCell* a, const JSValue b) { return JSValue(a) != b; }
+
+} // namespace JSC
+
+#endif // JSValue_h
diff --git a/Source/JavaScriptCore/runtime/JSValueInlineMethods.h b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h
new file mode 100644
index 000000000..e13d34745
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSValueInlineMethods.h
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef JSValueInlineMethods_h
+#define JSValueInlineMethods_h
+
+#include "JSValue.h"
+
+namespace JSC {
+
+ ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
+ {
+ if (isInt32())
+ return asInt32();
+ return JSC::toInt32(toNumber(exec));
+ }
+
+ inline uint32_t JSValue::toUInt32(ExecState* exec) const
+ {
+ // See comment on JSC::toUInt32, above.
+ return toInt32(exec);
+ }
+
+ inline bool JSValue::isUInt32() const
+ {
+ return isInt32() && asInt32() >= 0;
+ }
+
+ inline uint32_t JSValue::asUInt32() const
+ {
+ ASSERT(isUInt32());
+ return asInt32();
+ }
+
+ inline double JSValue::asNumber() const
+ {
+ ASSERT(isNumber());
+ return isInt32() ? asInt32() : asDouble();
+ }
+
+ inline JSValue jsNaN()
+ {
+ return JSValue(std::numeric_limits<double>::quiet_NaN());
+ }
+
+ inline JSValue::JSValue(char i)
+ {
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned char i)
+ {
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(short i)
+ {
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned short i)
+ {
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned i)
+ {
+ if (static_cast<int32_t>(i) < 0) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(long i)
+ {
+ if (static_cast<int32_t>(i) != i) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned long i)
+ {
+ if (static_cast<uint32_t>(i) != i) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<uint32_t>(i));
+ }
+
+ inline JSValue::JSValue(long long i)
+ {
+ if (static_cast<int32_t>(i) != i) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<int32_t>(i));
+ }
+
+ inline JSValue::JSValue(unsigned long long i)
+ {
+ if (static_cast<uint32_t>(i) != i) {
+ *this = JSValue(EncodeAsDouble, static_cast<double>(i));
+ return;
+ }
+ *this = JSValue(static_cast<uint32_t>(i));
+ }
+
+ inline JSValue::JSValue(double d)
+ {
+ const int32_t asInt32 = static_cast<int32_t>(d);
+ if (asInt32 != d || (!asInt32 && signbit(d))) { // true for -0.0
+ *this = JSValue(EncodeAsDouble, d);
+ return;
+ }
+ *this = JSValue(static_cast<int32_t>(d));
+ }
+
+#if USE(JSVALUE32_64)
+ inline EncodedJSValue JSValue::encode(JSValue value)
+ {
+ return value.u.asInt64;
+ }
+
+ inline JSValue JSValue::decode(EncodedJSValue encodedJSValue)
+ {
+ JSValue v;
+ v.u.asInt64 = encodedJSValue;
+ return v;
+ }
+
+ inline JSValue::JSValue()
+ {
+ u.asBits.tag = EmptyValueTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(JSNullTag)
+ {
+ u.asBits.tag = NullTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(JSUndefinedTag)
+ {
+ u.asBits.tag = UndefinedTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(JSTrueTag)
+ {
+ u.asBits.tag = BooleanTag;
+ u.asBits.payload = 1;
+ }
+
+ inline JSValue::JSValue(JSFalseTag)
+ {
+ u.asBits.tag = BooleanTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(HashTableDeletedValueTag)
+ {
+ u.asBits.tag = DeletedValueTag;
+ u.asBits.payload = 0;
+ }
+
+ inline JSValue::JSValue(JSCell* ptr)
+ {
+ if (ptr)
+ u.asBits.tag = CellTag;
+ else
+ u.asBits.tag = EmptyValueTag;
+ u.asBits.payload = reinterpret_cast<int32_t>(ptr);
+ }
+
+ inline JSValue::JSValue(const JSCell* ptr)
+ {
+ if (ptr)
+ u.asBits.tag = CellTag;
+ else
+ u.asBits.tag = EmptyValueTag;
+ u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr));
+ }
+
+ inline JSValue::operator bool() const
+ {
+ ASSERT(tag() != DeletedValueTag);
+ return tag() != EmptyValueTag;
+ }
+
+ inline bool JSValue::operator==(const JSValue& other) const
+ {
+ return u.asInt64 == other.u.asInt64;
+ }
+
+ inline bool JSValue::operator!=(const JSValue& other) const
+ {
+ return u.asInt64 != other.u.asInt64;
+ }
+
+ inline bool JSValue::isEmpty() const
+ {
+ return tag() == EmptyValueTag;
+ }
+
+ inline bool JSValue::isUndefined() const
+ {
+ return tag() == UndefinedTag;
+ }
+
+ inline bool JSValue::isNull() const
+ {
+ return tag() == NullTag;
+ }
+
+ inline bool JSValue::isUndefinedOrNull() const
+ {
+ return isUndefined() || isNull();
+ }
+
+ inline bool JSValue::isCell() const
+ {
+ return tag() == CellTag;
+ }
+
+ inline bool JSValue::isInt32() const
+ {
+ return tag() == Int32Tag;
+ }
+
+ inline bool JSValue::isDouble() const
+ {
+ return tag() < LowestTag;
+ }
+
+ inline bool JSValue::isTrue() const
+ {
+ return tag() == BooleanTag && payload();
+ }
+
+ inline bool JSValue::isFalse() const
+ {
+ return tag() == BooleanTag && !payload();
+ }
+
+ inline uint32_t JSValue::tag() const
+ {
+ return u.asBits.tag;
+ }
+
+ inline int32_t JSValue::payload() const
+ {
+ return u.asBits.payload;
+ }
+
+ inline int32_t JSValue::asInt32() const
+ {
+ ASSERT(isInt32());
+ return u.asBits.payload;
+ }
+
+ inline double JSValue::asDouble() const
+ {
+ ASSERT(isDouble());
+ return u.asDouble;
+ }
+
+ ALWAYS_INLINE JSCell* JSValue::asCell() const
+ {
+ ASSERT(isCell());
+ return reinterpret_cast<JSCell*>(u.asBits.payload);
+ }
+
+ ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
+ {
+ u.asDouble = d;
+ }
+
+ inline JSValue::JSValue(int i)
+ {
+ u.asBits.tag = Int32Tag;
+ u.asBits.payload = i;
+ }
+
+ inline bool JSValue::isNumber() const
+ {
+ return isInt32() || isDouble();
+ }
+
+ inline bool JSValue::isBoolean() const
+ {
+ return isTrue() || isFalse();
+ }
+
+ inline bool JSValue::asBoolean() const
+ {
+ ASSERT(isBoolean());
+ return payload();
+ }
+
+#else // USE(JSVALUE32_64)
+
+ // JSValue member functions.
+ inline EncodedJSValue JSValue::encode(JSValue value)
+ {
+ return value.u.ptr;
+ }
+
+ inline JSValue JSValue::decode(EncodedJSValue ptr)
+ {
+ return JSValue(reinterpret_cast<JSCell*>(ptr));
+ }
+
+ // 0x0 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x0, which is in the (invalid) zero page.
+ inline JSValue::JSValue()
+ {
+ u.asInt64 = ValueEmpty;
+ }
+
+ // 0x4 can never occur naturally because it has a tag of 00, indicating a pointer value, but a payload of 0x4, which is in the (invalid) zero page.
+ inline JSValue::JSValue(HashTableDeletedValueTag)
+ {
+ u.asInt64 = ValueDeleted;
+ }
+
+ inline JSValue::JSValue(JSCell* ptr)
+ {
+ u.ptr = ptr;
+ }
+
+ inline JSValue::JSValue(const JSCell* ptr)
+ {
+ u.ptr = const_cast<JSCell*>(ptr);
+ }
+
+ inline JSValue::operator bool() const
+ {
+ return u.ptr;
+ }
+
+ inline bool JSValue::operator==(const JSValue& other) const
+ {
+ return u.ptr == other.u.ptr;
+ }
+
+ inline bool JSValue::operator!=(const JSValue& other) const
+ {
+ return u.ptr != other.u.ptr;
+ }
+
+ inline bool JSValue::isEmpty() const
+ {
+ return u.asInt64 == ValueEmpty;
+ }
+
+ inline bool JSValue::isUndefined() const
+ {
+ return asValue() == JSValue(JSUndefined);
+ }
+
+ inline bool JSValue::isNull() const
+ {
+ return asValue() == JSValue(JSNull);
+ }
+
+ inline bool JSValue::isTrue() const
+ {
+ return asValue() == JSValue(JSTrue);
+ }
+
+ inline bool JSValue::isFalse() const
+ {
+ return asValue() == JSValue(JSFalse);
+ }
+
+ inline bool JSValue::asBoolean() const
+ {
+ ASSERT(isBoolean());
+ return asValue() == JSValue(JSTrue);
+ }
+
+ inline int32_t JSValue::asInt32() const
+ {
+ ASSERT(isInt32());
+ return static_cast<int32_t>(u.asInt64);
+ }
+
+ inline bool JSValue::isDouble() const
+ {
+ return isNumber() && !isInt32();
+ }
+
+ inline JSValue::JSValue(JSNullTag)
+ {
+ u.asInt64 = ValueNull;
+ }
+
+ inline JSValue::JSValue(JSUndefinedTag)
+ {
+ u.asInt64 = ValueUndefined;
+ }
+
+ inline JSValue::JSValue(JSTrueTag)
+ {
+ u.asInt64 = ValueTrue;
+ }
+
+ inline JSValue::JSValue(JSFalseTag)
+ {
+ u.asInt64 = ValueFalse;
+ }
+
+ inline bool JSValue::isUndefinedOrNull() const
+ {
+ // Undefined and null share the same value, bar the 'undefined' bit in the extended tag.
+ return (u.asInt64 & ~TagBitUndefined) == ValueNull;
+ }
+
+ inline bool JSValue::isBoolean() const
+ {
+ return (u.asInt64 & ~1) == ValueFalse;
+ }
+
+ inline bool JSValue::isCell() const
+ {
+ return !(u.asInt64 & TagMask);
+ }
+
+ inline bool JSValue::isInt32() const
+ {
+ return (u.asInt64 & TagTypeNumber) == TagTypeNumber;
+ }
+
+ inline intptr_t reinterpretDoubleToIntptr(double value)
+ {
+ return bitwise_cast<intptr_t>(value);
+ }
+ inline double reinterpretIntptrToDouble(intptr_t value)
+ {
+ return bitwise_cast<double>(value);
+ }
+
+ ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, double d)
+ {
+ u.asInt64 = reinterpretDoubleToIntptr(d) + DoubleEncodeOffset;
+ }
+
+ inline JSValue::JSValue(int i)
+ {
+ u.asInt64 = TagTypeNumber | static_cast<uint32_t>(i);
+ }
+
+ inline double JSValue::asDouble() const
+ {
+ return reinterpretIntptrToDouble(u.asInt64 - DoubleEncodeOffset);
+ }
+
+ inline bool JSValue::isNumber() const
+ {
+ return u.asInt64 & TagTypeNumber;
+ }
+
+ ALWAYS_INLINE JSCell* JSValue::asCell() const
+ {
+ ASSERT(isCell());
+ return u.ptr;
+ }
+
+#endif // USE(JSVALUE64)
+
+} // namespace JSC
+
+#endif // JSValueInlineMethods_h
diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.cpp b/Source/JavaScriptCore/runtime/JSVariableObject.cpp
new file mode 100644
index 000000000..706e3debb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSVariableObject.cpp
@@ -0,0 +1,98 @@
+/*
+ * 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 "JSActivation.h"
+#include "JSGlobalObject.h"
+#include "JSStaticScopeObject.h"
+#include "PropertyNameArray.h"
+#include "PropertyDescriptor.h"
+
+namespace JSC {
+
+void JSVariableObject::destroy(JSCell* cell)
+{
+ jsCast<JSVariableObject*>(cell)->JSVariableObject::~JSVariableObject();
+}
+
+bool JSVariableObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
+{
+ JSVariableObject* thisObject = jsCast<JSVariableObject*>(cell);
+ if (thisObject->symbolTable().contains(propertyName.impl()))
+ return false;
+
+ return JSObject::deleteProperty(thisObject, exec, propertyName);
+}
+
+void JSVariableObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ JSVariableObject* thisObject = jsCast<JSVariableObject*>(object);
+ SymbolTable::const_iterator end = thisObject->symbolTable().end();
+ for (SymbolTable::const_iterator it = thisObject->symbolTable().begin(); it != end; ++it) {
+ if (!(it->second.getAttributes() & DontEnum) || (mode == IncludeDontEnumProperties))
+ propertyNames.add(Identifier(exec, it->first.get()));
+ }
+
+ JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ if (!entry.isNull()) {
+ descriptor.setDescriptor(registerAt(entry.getIndex()).get(), entry.getAttributes() | DontDelete);
+ return true;
+ }
+ return false;
+}
+
+void JSVariableObject::putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned)
+{
+ ASSERT_NOT_REACHED();
+}
+
+bool JSVariableObject::isDynamicScope(bool& requiresDynamicChecks) const
+{
+ switch (structure()->typeInfo().type()) {
+ case GlobalObjectType:
+ return static_cast<const JSGlobalObject*>(this)->isDynamicScope(requiresDynamicChecks);
+ case ActivationObjectType:
+ return static_cast<const JSActivation*>(this)->isDynamicScope(requiresDynamicChecks);
+ case StaticScopeObjectType:
+ return static_cast<const JSStaticScopeObject*>(this)->isDynamicScope(requiresDynamicChecks);
+ default:
+ ASSERT_NOT_REACHED();
+ break;
+ }
+
+ return false;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSVariableObject.h b/Source/JavaScriptCore/runtime/JSVariableObject.h
new file mode 100644
index 000000000..78e624e02
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSVariableObject.h
@@ -0,0 +1,173 @@
+/*
+ * 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 JSNonFinalObject {
+ friend class JIT;
+
+ public:
+ typedef JSNonFinalObject Base;
+
+ SymbolTable& symbolTable() const { return *m_symbolTable; }
+
+ static void destroy(JSCell*);
+
+ static NO_RETURN_DUE_TO_ASSERT void putWithAttributes(JSObject*, ExecState*, const Identifier&, JSValue, unsigned attributes);
+
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier&);
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
+ bool isDynamicScope(bool& requiresDynamicChecks) const;
+
+ WriteBarrier<Unknown>& registerAt(int index) const { return m_registers[index]; }
+
+ WriteBarrier<Unknown>* const * addressOfRegisters() const { return &m_registers; }
+ static size_t offsetOfRegisters() { return OBJECT_OFFSETOF(JSVariableObject, m_registers); }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(VariableObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetPropertyNames | JSNonFinalObject::StructureFlags;
+
+ JSVariableObject(JSGlobalData& globalData, Structure* structure, SymbolTable* symbolTable, Register* registers)
+ : JSNonFinalObject(globalData, structure)
+ , m_symbolTable(symbolTable)
+ , m_registers(reinterpret_cast<WriteBarrier<Unknown>*>(registers))
+ {
+ }
+
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData);
+ ASSERT(m_symbolTable);
+ COMPILE_ASSERT(sizeof(WriteBarrier<Unknown>) == sizeof(Register), Register_should_be_same_size_as_WriteBarrier);
+ }
+
+ PassOwnArrayPtr<WriteBarrier<Unknown> > copyRegisterArray(JSGlobalData&, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts);
+ void setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray);
+
+ bool symbolTableGet(const Identifier&, PropertySlot&);
+ bool symbolTableGet(const Identifier&, PropertyDescriptor&);
+ bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable);
+ bool symbolTablePut(ExecState*, const Identifier&, JSValue, bool shouldThrow);
+ bool symbolTablePutWithAttributes(JSGlobalData&, const Identifier&, JSValue, unsigned attributes);
+
+ SymbolTable* m_symbolTable; // Maps name -> offset from "r" in register file.
+ WriteBarrier<Unknown>* m_registers; // "r" in the register file.
+ OwnArrayPtr<WriteBarrier<Unknown> > m_registerArray; // Independent copy of registers, used when a variable object copies its registers out of the register file.
+ };
+
+ inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
+ {
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ if (!entry.isNull()) {
+ slot.setValue(registerAt(entry.getIndex()).get());
+ return true;
+ }
+ return false;
+ }
+
+ inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot, bool& slotIsWriteable)
+ {
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ if (!entry.isNull()) {
+ slot.setValue(registerAt(entry.getIndex()).get());
+ slotIsWriteable = !entry.isReadOnly();
+ return true;
+ }
+ return false;
+ }
+
+ inline bool JSVariableObject::symbolTablePut(ExecState* exec, const Identifier& propertyName, JSValue value, bool shouldThrow)
+ {
+ JSGlobalData& globalData = exec->globalData();
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+
+ SymbolTableEntry entry = symbolTable().inlineGet(propertyName.impl());
+ if (entry.isNull())
+ return false;
+ if (entry.isReadOnly()) {
+ if (shouldThrow)
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+ return true;
+ }
+ registerAt(entry.getIndex()).set(globalData, this, value);
+ return true;
+ }
+
+ inline bool JSVariableObject::symbolTablePutWithAttributes(JSGlobalData& globalData, const Identifier& propertyName, JSValue value, unsigned attributes)
+ {
+ ASSERT(!Heap::heap(value) || Heap::heap(value) == Heap::heap(this));
+
+ SymbolTable::iterator iter = symbolTable().find(propertyName.impl());
+ if (iter == symbolTable().end())
+ return false;
+ SymbolTableEntry& entry = iter->second;
+ ASSERT(!entry.isNull());
+ entry.setAttributes(attributes);
+ registerAt(entry.getIndex()).set(globalData, this, value);
+ return true;
+ }
+
+ inline PassOwnArrayPtr<WriteBarrier<Unknown> > JSVariableObject::copyRegisterArray(JSGlobalData& globalData, WriteBarrier<Unknown>* src, size_t count, size_t callframeStarts)
+ {
+ OwnArrayPtr<WriteBarrier<Unknown> > registerArray = adoptArrayPtr(new WriteBarrier<Unknown>[count]);
+ for (size_t i = 0; i < callframeStarts; i++)
+ registerArray[i].set(globalData, this, src[i].get());
+ for (size_t i = callframeStarts + RegisterFile::CallFrameHeaderSize; i < count; i++)
+ registerArray[i].set(globalData, this, src[i].get());
+
+ return registerArray.release();
+ }
+
+ inline void JSVariableObject::setRegisters(WriteBarrier<Unknown>* registers, PassOwnArrayPtr<WriteBarrier<Unknown> > registerArray)
+ {
+ ASSERT(registerArray != m_registerArray);
+ m_registerArray = registerArray;
+ m_registers = registers;
+ }
+
+} // namespace JSC
+
+#endif // JSVariableObject_h
diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.cpp b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp
new file mode 100644
index 000000000..f8f5727d8
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSWrapperObject.cpp
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2006 Maks Orlovich
+ * Copyright (C) 2006, 2009 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 "JSWrapperObject.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(JSWrapperObject);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(JSWrapperObject);
+
+void JSWrapperObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ JSWrapperObject* thisObject = jsCast<JSWrapperObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ JSObject::visitChildren(thisObject, visitor);
+ if (thisObject->m_internalValue)
+ visitor.append(&thisObject->m_internalValue);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/JSWrapperObject.h b/Source/JavaScriptCore/runtime/JSWrapperObject.h
new file mode 100644
index 000000000..65b4bdb7f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/JSWrapperObject.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006 Maks Orlovich
+ * Copyright (C) 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef JSWrapperObject_h
+#define JSWrapperObject_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+ // This class is used as a base for classes such as String,
+ // Number, Boolean and Date which are wrappers for primitive types.
+ class JSWrapperObject : public JSNonFinalObject {
+ public:
+ typedef JSNonFinalObject Base;
+
+ JSValue internalValue() const;
+ void setInternalValue(JSGlobalData&, JSValue);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ explicit JSWrapperObject(JSGlobalData&, Structure*);
+ static const unsigned StructureFlags = OverridesVisitChildren | JSNonFinalObject::StructureFlags;
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ private:
+ WriteBarrier<Unknown> m_internalValue;
+ };
+
+ inline JSWrapperObject::JSWrapperObject(JSGlobalData& globalData, Structure* structure)
+ : JSNonFinalObject(globalData, structure)
+ {
+ }
+
+ inline JSValue JSWrapperObject::internalValue() const
+ {
+ return m_internalValue.get();
+ }
+
+ inline void JSWrapperObject::setInternalValue(JSGlobalData& globalData, JSValue value)
+ {
+ ASSERT(value);
+ ASSERT(!value.isObject());
+ m_internalValue.set(globalData, this, value);
+ }
+
+} // namespace JSC
+
+#endif // JSWrapperObject_h
diff --git a/Source/JavaScriptCore/runtime/LiteralParser.cpp b/Source/JavaScriptCore/runtime/LiteralParser.cpp
new file mode 100644
index 000000000..b22b81503
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/LiteralParser.cpp
@@ -0,0 +1,829 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "LiteralParser.h"
+
+#include "JSArray.h"
+#include "JSString.h"
+#include "Lexer.h"
+#include "StrongInlines.h"
+#include "UStringBuilder.h"
+#include <wtf/ASCIICType.h>
+#include <wtf/dtoa.h>
+
+namespace JSC {
+
+template <typename CharType>
+static inline bool isJSONWhiteSpace(const CharType& c)
+{
+ // The JSON RFC 4627 defines a list of allowed characters to be considered
+ // insignificant white space: http://www.ietf.org/rfc/rfc4627.txt (2. JSON Grammar).
+ return c == ' ' || c == 0x9 || c == 0xA || c == 0xD;
+}
+
+template <typename CharType>
+bool LiteralParser<CharType>::tryJSONPParse(Vector<JSONPData>& results, bool needsFullSourceInfo)
+{
+ if (m_lexer.next() != TokIdentifier)
+ return false;
+ do {
+ Vector<JSONPPathEntry> path;
+ // Unguarded next to start off the lexer
+ Identifier name = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ JSONPPathEntry entry;
+ if (name == m_exec->globalData().propertyNames->varKeyword) {
+ if (m_lexer.next() != TokIdentifier)
+ return false;
+ entry.m_type = JSONPPathEntryTypeDeclare;
+ entry.m_pathEntryName = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ path.append(entry);
+ } else {
+ entry.m_type = JSONPPathEntryTypeDot;
+ entry.m_pathEntryName = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ path.append(entry);
+ }
+ if (m_exec->globalData().keywords->isKeyword(entry.m_pathEntryName))
+ return false;
+ TokenType tokenType = m_lexer.next();
+ while (tokenType != TokAssign) {
+ switch (tokenType) {
+ case TokLBracket: {
+ entry.m_type = JSONPPathEntryTypeLookup;
+ if (m_lexer.next() != TokNumber)
+ return false;
+ double doubleIndex = m_lexer.currentToken().numberToken;
+ int index = (int)doubleIndex;
+ if (index != doubleIndex || index < 0)
+ return false;
+ entry.m_pathIndex = index;
+ if (m_lexer.next() != TokRBracket)
+ return false;
+ break;
+ }
+ case TokDot: {
+ entry.m_type = JSONPPathEntryTypeDot;
+ if (m_lexer.next() != TokIdentifier)
+ return false;
+ entry.m_pathEntryName = Identifier(&m_exec->globalData(), m_lexer.currentToken().start, m_lexer.currentToken().end - m_lexer.currentToken().start);
+ break;
+ }
+ case TokLParen: {
+ if (path.last().m_type != JSONPPathEntryTypeDot || needsFullSourceInfo)
+ return false;
+ path.last().m_type = JSONPPathEntryTypeCall;
+ entry = path.last();
+ goto startJSON;
+ }
+ default:
+ return false;
+ }
+ path.append(entry);
+ tokenType = m_lexer.next();
+ }
+ startJSON:
+ m_lexer.next();
+ results.append(JSONPData());
+ results.last().m_value.set(m_exec->globalData(), parse(StartParseExpression));
+ if (!results.last().m_value)
+ return false;
+ results.last().m_path.swap(path);
+ if (entry.m_type == JSONPPathEntryTypeCall) {
+ if (m_lexer.currentToken().type != TokRParen)
+ return false;
+ m_lexer.next();
+ }
+ if (m_lexer.currentToken().type != TokSemi)
+ break;
+ m_lexer.next();
+ } while (m_lexer.currentToken().type == TokIdentifier);
+ return m_lexer.currentToken().type == TokEnd;
+}
+
+template <typename CharType>
+ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const LChar* characters, size_t length)
+{
+ if (!length)
+ return m_exec->globalData().propertyNames->emptyIdentifier;
+ if (characters[0] >= MaximumCachableCharacter)
+ return Identifier(&m_exec->globalData(), characters, length);
+
+ if (length == 1) {
+ if (!m_shortIdentifiers[characters[0]].isNull())
+ return m_shortIdentifiers[characters[0]];
+ m_shortIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length);
+ return m_shortIdentifiers[characters[0]];
+ }
+ if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length))
+ return m_recentIdentifiers[characters[0]];
+ m_recentIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length);
+ return m_recentIdentifiers[characters[0]];
+}
+
+template <typename CharType>
+ALWAYS_INLINE const Identifier LiteralParser<CharType>::makeIdentifier(const UChar* characters, size_t length)
+{
+ if (!length)
+ return m_exec->globalData().propertyNames->emptyIdentifier;
+ if (characters[0] >= MaximumCachableCharacter)
+ return Identifier(&m_exec->globalData(), characters, length);
+
+ if (length == 1) {
+ if (!m_shortIdentifiers[characters[0]].isNull())
+ return m_shortIdentifiers[characters[0]];
+ m_shortIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length);
+ return m_shortIdentifiers[characters[0]];
+ }
+ if (!m_recentIdentifiers[characters[0]].isNull() && Identifier::equal(m_recentIdentifiers[characters[0]].impl(), characters, length))
+ return m_recentIdentifiers[characters[0]];
+ m_recentIdentifiers[characters[0]] = Identifier(&m_exec->globalData(), characters, length);
+ return m_recentIdentifiers[characters[0]];
+}
+
+template <typename CharType>
+template <ParserMode mode> TokenType LiteralParser<CharType>::Lexer::lex(LiteralParserToken<CharType>& token)
+{
+ while (m_ptr < m_end && isJSONWhiteSpace(*m_ptr))
+ ++m_ptr;
+
+ ASSERT(m_ptr <= m_end);
+ if (m_ptr >= m_end) {
+ token.type = TokEnd;
+ token.start = token.end = m_ptr;
+ return TokEnd;
+ }
+ token.type = TokError;
+ token.start = m_ptr;
+ switch (*m_ptr) {
+ case '[':
+ token.type = TokLBracket;
+ token.end = ++m_ptr;
+ return TokLBracket;
+ case ']':
+ token.type = TokRBracket;
+ token.end = ++m_ptr;
+ return TokRBracket;
+ case '(':
+ token.type = TokLParen;
+ token.end = ++m_ptr;
+ return TokLParen;
+ case ')':
+ token.type = TokRParen;
+ token.end = ++m_ptr;
+ return TokRParen;
+ case '{':
+ token.type = TokLBrace;
+ token.end = ++m_ptr;
+ return TokLBrace;
+ case '}':
+ token.type = TokRBrace;
+ token.end = ++m_ptr;
+ return TokRBrace;
+ case ',':
+ token.type = TokComma;
+ token.end = ++m_ptr;
+ return TokComma;
+ case ':':
+ token.type = TokColon;
+ token.end = ++m_ptr;
+ return TokColon;
+ case '"':
+ return lexString<mode, '"'>(token);
+ case 't':
+ if (m_end - m_ptr >= 4 && m_ptr[1] == 'r' && m_ptr[2] == 'u' && m_ptr[3] == 'e') {
+ m_ptr += 4;
+ token.type = TokTrue;
+ token.end = m_ptr;
+ return TokTrue;
+ }
+ break;
+ case 'f':
+ if (m_end - m_ptr >= 5 && m_ptr[1] == 'a' && m_ptr[2] == 'l' && m_ptr[3] == 's' && m_ptr[4] == 'e') {
+ m_ptr += 5;
+ token.type = TokFalse;
+ token.end = m_ptr;
+ return TokFalse;
+ }
+ break;
+ case 'n':
+ if (m_end - m_ptr >= 4 && m_ptr[1] == 'u' && m_ptr[2] == 'l' && m_ptr[3] == 'l') {
+ m_ptr += 4;
+ token.type = TokNull;
+ token.end = m_ptr;
+ return TokNull;
+ }
+ break;
+ case '-':
+ case '0':
+ case '1':
+ case '2':
+ case '3':
+ case '4':
+ case '5':
+ case '6':
+ case '7':
+ case '8':
+ case '9':
+ return lexNumber(token);
+ }
+ if (m_ptr < m_end) {
+ if (*m_ptr == '.') {
+ token.type = TokDot;
+ token.end = ++m_ptr;
+ return TokDot;
+ }
+ if (*m_ptr == '=') {
+ token.type = TokAssign;
+ token.end = ++m_ptr;
+ return TokAssign;
+ }
+ if (*m_ptr == ';') {
+ token.type = TokSemi;
+ token.end = ++m_ptr;
+ return TokAssign;
+ }
+ if (isASCIIAlpha(*m_ptr) || *m_ptr == '_' || *m_ptr == '$')
+ return lexIdentifier(token);
+ if (*m_ptr == '\'') {
+ if (mode == StrictJSON) {
+ m_lexErrorMessage = "Single quotes (\') are not allowed in JSON";
+ return TokError;
+ }
+ return lexString<mode, '\''>(token);
+ }
+ }
+ m_lexErrorMessage = String::format("Unrecognized token '%c'", *m_ptr).impl();
+ return TokError;
+}
+
+template <>
+ALWAYS_INLINE TokenType LiteralParser<LChar>::Lexer::lexIdentifier(LiteralParserToken<LChar>& token)
+{
+ while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$'))
+ m_ptr++;
+ token.stringIs8Bit = 1;
+ token.stringToken8 = token.start;
+ token.stringLength = m_ptr - token.start;
+ token.type = TokIdentifier;
+ token.end = m_ptr;
+ return TokIdentifier;
+}
+
+template <>
+ALWAYS_INLINE TokenType LiteralParser<UChar>::Lexer::lexIdentifier(LiteralParserToken<UChar>& token)
+{
+ while (m_ptr < m_end && (isASCIIAlphanumeric(*m_ptr) || *m_ptr == '_' || *m_ptr == '$'))
+ m_ptr++;
+ token.stringIs8Bit = 0;
+ token.stringToken16 = token.start;
+ token.stringLength = m_ptr - token.start;
+ token.type = TokIdentifier;
+ token.end = m_ptr;
+ return TokIdentifier;
+}
+
+template <typename CharType>
+TokenType LiteralParser<CharType>::Lexer::next()
+{
+ if (m_mode == NonStrictJSON)
+ return lex<NonStrictJSON>(m_currentToken);
+ if (m_mode == JSONP)
+ return lex<JSONP>(m_currentToken);
+ return lex<StrictJSON>(m_currentToken);
+}
+
+template <>
+ALWAYS_INLINE void setParserTokenString<LChar>(LiteralParserToken<LChar>& token, const LChar* string)
+{
+ token.stringIs8Bit = 1;
+ token.stringToken8 = string;
+}
+
+template <>
+ALWAYS_INLINE void setParserTokenString<UChar>(LiteralParserToken<UChar>& token, const UChar* string)
+{
+ token.stringIs8Bit = 0;
+ token.stringToken16 = string;
+}
+
+template <ParserMode mode, typename CharType, LChar terminator> static inline bool isSafeStringCharacter(LChar c)
+{
+ return (c >= ' ' && c != '\\' && c != terminator) || (c == '\t' && mode != StrictJSON);
+}
+
+template <ParserMode mode, typename CharType, UChar terminator> static inline bool isSafeStringCharacter(UChar c)
+{
+ return (c >= ' ' && (mode == StrictJSON || c <= 0xff) && c != '\\' && c != terminator) || (c == '\t' && mode != StrictJSON);
+}
+
+template <typename CharType>
+template <ParserMode mode, char terminator> ALWAYS_INLINE TokenType LiteralParser<CharType>::Lexer::lexString(LiteralParserToken<CharType>& token)
+{
+ ++m_ptr;
+ const CharType* runStart = m_ptr;
+ UStringBuilder builder;
+ do {
+ runStart = m_ptr;
+ while (m_ptr < m_end && isSafeStringCharacter<mode, CharType, terminator>(*m_ptr))
+ ++m_ptr;
+ if (builder.length())
+ builder.append(runStart, m_ptr - runStart);
+ if ((mode != NonStrictJSON) && m_ptr < m_end && *m_ptr == '\\') {
+ if (builder.isEmpty() && runStart < m_ptr)
+ builder.append(runStart, m_ptr - runStart);
+ ++m_ptr;
+ if (m_ptr >= m_end) {
+ m_lexErrorMessage = "Unterminated string";
+ return TokError;
+ }
+ switch (*m_ptr) {
+ case '"':
+ builder.append('"');
+ m_ptr++;
+ break;
+ case '\\':
+ builder.append('\\');
+ m_ptr++;
+ break;
+ case '/':
+ builder.append('/');
+ m_ptr++;
+ break;
+ case 'b':
+ builder.append('\b');
+ m_ptr++;
+ break;
+ case 'f':
+ builder.append('\f');
+ m_ptr++;
+ break;
+ case 'n':
+ builder.append('\n');
+ m_ptr++;
+ break;
+ case 'r':
+ builder.append('\r');
+ m_ptr++;
+ break;
+ case 't':
+ builder.append('\t');
+ m_ptr++;
+ break;
+
+ case 'u':
+ if ((m_end - m_ptr) < 5) {
+ m_lexErrorMessage = "\\u must be followed by 4 hex digits";
+ return TokError;
+ } // uNNNN == 5 characters
+ for (int i = 1; i < 5; i++) {
+ if (!isASCIIHexDigit(m_ptr[i])) {
+ m_lexErrorMessage = String::format("\"\\%s\" is not a valid unicode escape", UString(m_ptr, 5).ascii().data()).impl();
+ return TokError;
+ }
+ }
+ builder.append(JSC::Lexer<CharType>::convertUnicode(m_ptr[1], m_ptr[2], m_ptr[3], m_ptr[4]));
+ m_ptr += 5;
+ break;
+
+ default:
+ if (*m_ptr == '\'' && mode != StrictJSON) {
+ builder.append('\'');
+ m_ptr++;
+ break;
+ }
+ m_lexErrorMessage = String::format("Invalid escape character %c", *m_ptr).impl();
+ return TokError;
+ }
+ }
+ } while ((mode != NonStrictJSON) && m_ptr != runStart && (m_ptr < m_end) && *m_ptr != terminator);
+
+ if (m_ptr >= m_end || *m_ptr != terminator) {
+ m_lexErrorMessage = "Unterminated string";
+ return TokError;
+ }
+
+ if (builder.isEmpty()) {
+ token.stringBuffer = UString();
+ setParserTokenString<CharType>(token, runStart);
+ token.stringLength = m_ptr - runStart;
+ } else {
+ token.stringBuffer = builder.toUString();
+ if (token.stringBuffer.is8Bit()) {
+ token.stringIs8Bit = 1;
+ token.stringToken8 = token.stringBuffer.characters8();
+ } else {
+ token.stringIs8Bit = 0;
+ token.stringToken16 = token.stringBuffer.characters16();
+ }
+ token.stringLength = token.stringBuffer.length();
+ }
+ token.type = TokString;
+ token.end = ++m_ptr;
+ return TokString;
+}
+
+template <typename CharType>
+TokenType LiteralParser<CharType>::Lexer::lexNumber(LiteralParserToken<CharType>& token)
+{
+ // ES5 and json.org define numbers as
+ // number
+ // int
+ // int frac? exp?
+ //
+ // int
+ // -? 0
+ // -? digit1-9 digits?
+ //
+ // digits
+ // digit digits?
+ //
+ // -?(0 | [1-9][0-9]*) ('.' [0-9]+)? ([eE][+-]? [0-9]+)?
+
+ if (m_ptr < m_end && *m_ptr == '-') // -?
+ ++m_ptr;
+
+ // (0 | [1-9][0-9]*)
+ if (m_ptr < m_end && *m_ptr == '0') // 0
+ ++m_ptr;
+ else if (m_ptr < m_end && *m_ptr >= '1' && *m_ptr <= '9') { // [1-9]
+ ++m_ptr;
+ // [0-9]*
+ while (m_ptr < m_end && isASCIIDigit(*m_ptr))
+ ++m_ptr;
+ } else {
+ m_lexErrorMessage = "Invalid number";
+ return TokError;
+ }
+
+ // ('.' [0-9]+)?
+ if (m_ptr < m_end && *m_ptr == '.') {
+ ++m_ptr;
+ // [0-9]+
+ if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) {
+ m_lexErrorMessage = "Invalid digits after decimal point";
+ return TokError;
+ }
+
+ ++m_ptr;
+ while (m_ptr < m_end && isASCIIDigit(*m_ptr))
+ ++m_ptr;
+ } else if (m_ptr < m_end && (*m_ptr != 'e' && *m_ptr != 'E') && (m_ptr - token.start) < 10) {
+ int result = 0;
+ token.type = TokNumber;
+ token.end = m_ptr;
+ const CharType* digit = token.start;
+ int negative = 1;
+ if (*digit == '-') {
+ negative = -1;
+ digit++;
+ }
+
+ while (digit < m_ptr)
+ result = result * 10 + (*digit++) - '0';
+ result *= negative;
+ token.numberToken = result;
+ return TokNumber;
+ }
+
+ // ([eE][+-]? [0-9]+)?
+ if (m_ptr < m_end && (*m_ptr == 'e' || *m_ptr == 'E')) { // [eE]
+ ++m_ptr;
+
+ // [-+]?
+ if (m_ptr < m_end && (*m_ptr == '-' || *m_ptr == '+'))
+ ++m_ptr;
+
+ // [0-9]+
+ if (m_ptr >= m_end || !isASCIIDigit(*m_ptr)) {
+ m_lexErrorMessage = "Exponent symbols should be followed by an optional '+' or '-' and then by at least one number";
+ return TokError;
+ }
+
+ ++m_ptr;
+ while (m_ptr < m_end && isASCIIDigit(*m_ptr))
+ ++m_ptr;
+ }
+
+ token.type = TokNumber;
+ token.end = m_ptr;
+ Vector<char, 64> buffer(token.end - token.start + 1);
+ int i;
+ for (i = 0; i < token.end - token.start; i++) {
+ ASSERT(static_cast<char>(token.start[i]) == token.start[i]);
+ buffer[i] = static_cast<char>(token.start[i]);
+ }
+ buffer[i] = 0;
+ char* end;
+ token.numberToken = WTF::strtod(buffer.data(), &end);
+ ASSERT(buffer.data() + (token.end - token.start) == end);
+ return TokNumber;
+}
+
+template <typename CharType>
+JSValue LiteralParser<CharType>::parse(ParserState initialState)
+{
+ ParserState state = initialState;
+ MarkedArgumentBuffer objectStack;
+ JSValue lastValue;
+ Vector<ParserState, 16> stateStack;
+ Vector<Identifier, 16> identifierStack;
+ while (1) {
+ switch(state) {
+ startParseArray:
+ case StartParseArray: {
+ JSArray* array = constructEmptyArray(m_exec);
+ objectStack.append(array);
+ // fallthrough
+ }
+ doParseArrayStartExpression:
+ case DoParseArrayStartExpression: {
+ TokenType lastToken = m_lexer.currentToken().type;
+ if (m_lexer.next() == TokRBracket) {
+ if (lastToken == TokComma) {
+ m_parseErrorMessage = "Unexpected comma at the end of array expression";
+ return JSValue();
+ }
+ m_lexer.next();
+ lastValue = objectStack.last();
+ objectStack.removeLast();
+ break;
+ }
+
+ stateStack.append(DoParseArrayEndExpression);
+ goto startParseExpression;
+ }
+ case DoParseArrayEndExpression: {
+ asArray(objectStack.last())->push(m_exec, lastValue);
+
+ if (m_lexer.currentToken().type == TokComma)
+ goto doParseArrayStartExpression;
+
+ if (m_lexer.currentToken().type != TokRBracket) {
+ m_parseErrorMessage = "Expected ']'";
+ return JSValue();
+ }
+
+ m_lexer.next();
+ lastValue = objectStack.last();
+ objectStack.removeLast();
+ break;
+ }
+ startParseObject:
+ case StartParseObject: {
+ JSObject* object = constructEmptyObject(m_exec);
+ objectStack.append(object);
+
+ TokenType type = m_lexer.next();
+ if (type == TokString || (m_mode != StrictJSON && type == TokIdentifier)) {
+ LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
+
+ // Check for colon
+ if (m_lexer.next() != TokColon) {
+ m_parseErrorMessage = "Expected ':' before value in object property definition";
+ return JSValue();
+ }
+
+ m_lexer.next();
+ if (identifierToken.stringIs8Bit)
+ identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
+ else
+ identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
+ stateStack.append(DoParseObjectEndExpression);
+ goto startParseExpression;
+ }
+ if (type != TokRBrace) {
+ m_parseErrorMessage = "Expected '}'";
+ return JSValue();
+ }
+ m_lexer.next();
+ lastValue = objectStack.last();
+ objectStack.removeLast();
+ break;
+ }
+ doParseObjectStartExpression:
+ case DoParseObjectStartExpression: {
+ TokenType type = m_lexer.next();
+ if (type != TokString && (m_mode == StrictJSON || type != TokIdentifier)) {
+ m_parseErrorMessage = "Property name must be a string literal";
+ return JSValue();
+ }
+ LiteralParserToken<CharType> identifierToken = m_lexer.currentToken();
+
+ // Check for colon
+ if (m_lexer.next() != TokColon) {
+ m_parseErrorMessage = "Expected ':'";
+ return JSValue();
+ }
+
+ m_lexer.next();
+ if (identifierToken.stringIs8Bit)
+ identifierStack.append(makeIdentifier(identifierToken.stringToken8, identifierToken.stringLength));
+ else
+ identifierStack.append(makeIdentifier(identifierToken.stringToken16, identifierToken.stringLength));
+ stateStack.append(DoParseObjectEndExpression);
+ goto startParseExpression;
+ }
+ case DoParseObjectEndExpression:
+ {
+ asObject(objectStack.last())->putDirect(m_exec->globalData(), identifierStack.last(), lastValue);
+ identifierStack.removeLast();
+ if (m_lexer.currentToken().type == TokComma)
+ goto doParseObjectStartExpression;
+ if (m_lexer.currentToken().type != TokRBrace) {
+ m_parseErrorMessage = "Expected '}'";
+ return JSValue();
+ }
+ m_lexer.next();
+ lastValue = objectStack.last();
+ objectStack.removeLast();
+ break;
+ }
+ startParseExpression:
+ case StartParseExpression: {
+ switch (m_lexer.currentToken().type) {
+ case TokLBracket:
+ goto startParseArray;
+ case TokLBrace:
+ goto startParseObject;
+ case TokString: {
+ LiteralParserToken<CharType> stringToken = m_lexer.currentToken();
+ m_lexer.next();
+ if (stringToken.stringIs8Bit)
+ lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken8, stringToken.stringLength).ustring());
+ else
+ lastValue = jsString(m_exec, makeIdentifier(stringToken.stringToken16, stringToken.stringLength).ustring());
+ break;
+ }
+ case TokNumber: {
+ LiteralParserToken<CharType> numberToken = m_lexer.currentToken();
+ m_lexer.next();
+ lastValue = jsNumber(numberToken.numberToken);
+ break;
+ }
+ case TokNull:
+ m_lexer.next();
+ lastValue = jsNull();
+ break;
+
+ case TokTrue:
+ m_lexer.next();
+ lastValue = jsBoolean(true);
+ break;
+
+ case TokFalse:
+ m_lexer.next();
+ lastValue = jsBoolean(false);
+ break;
+ case TokRBracket:
+ m_parseErrorMessage = "Unexpected token ']'";
+ return JSValue();
+ case TokRBrace:
+ m_parseErrorMessage = "Unexpected token '}'";
+ return JSValue();
+ case TokIdentifier: {
+ const LiteralParserToken<CharType>& token = m_lexer.currentToken();
+ if (token.stringIs8Bit)
+ m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", UString(m_lexer.currentToken().stringToken8, m_lexer.currentToken().stringLength).ascii().data()).impl();
+ else
+ m_parseErrorMessage = String::format("Unexpected identifier \"%s\"", UString(m_lexer.currentToken().stringToken16, m_lexer.currentToken().stringLength).ascii().data()).impl();
+ return JSValue();
+ }
+ case TokColon:
+ m_parseErrorMessage = "Unexpected token ':'";
+ return JSValue();
+ case TokLParen:
+ m_parseErrorMessage = "Unexpected token '('";
+ return JSValue();
+ case TokRParen:
+ m_parseErrorMessage = "Unexpected token ')'";
+ return JSValue();
+ case TokComma:
+ m_parseErrorMessage = "Unexpected token ','";
+ return JSValue();
+ case TokDot:
+ m_parseErrorMessage = "Unexpected token '.'";
+ return JSValue();
+ case TokAssign:
+ m_parseErrorMessage = "Unexpected token '='";
+ return JSValue();
+ case TokSemi:
+ m_parseErrorMessage = "Unexpected token ';'";
+ return JSValue();
+ case TokEnd:
+ m_parseErrorMessage = "Unexpected EOF";
+ return JSValue();
+ case TokError:
+ default:
+ // Error
+ m_parseErrorMessage = "Could not parse value expression";
+ return JSValue();
+ }
+ break;
+ }
+ case StartParseStatement: {
+ switch (m_lexer.currentToken().type) {
+ case TokLBracket:
+ case TokNumber:
+ case TokString:
+ goto startParseExpression;
+
+ case TokLParen: {
+ m_lexer.next();
+ stateStack.append(StartParseStatementEndStatement);
+ goto startParseExpression;
+ }
+ case TokRBracket:
+ m_parseErrorMessage = "Unexpected token ']'";
+ return JSValue();
+ case TokLBrace:
+ m_parseErrorMessage = "Unexpected token '{'";
+ return JSValue();
+ case TokRBrace:
+ m_parseErrorMessage = "Unexpected token '}'";
+ return JSValue();
+ case TokIdentifier:
+ m_parseErrorMessage = "Unexpected identifier";
+ return JSValue();
+ case TokColon:
+ m_parseErrorMessage = "Unexpected token ':'";
+ return JSValue();
+ case TokRParen:
+ m_parseErrorMessage = "Unexpected token ')'";
+ return JSValue();
+ case TokComma:
+ m_parseErrorMessage = "Unexpected token ','";
+ return JSValue();
+ case TokTrue:
+ m_parseErrorMessage = "Unexpected token 'true'";
+ return JSValue();
+ case TokFalse:
+ m_parseErrorMessage = "Unexpected token 'false'";
+ return JSValue();
+ case TokNull:
+ m_parseErrorMessage = "Unexpected token 'null'";
+ return JSValue();
+ case TokEnd:
+ m_parseErrorMessage = "Unexpected EOF";
+ return JSValue();
+ case TokDot:
+ m_parseErrorMessage = "Unexpected token '.'";
+ return JSValue();
+ case TokAssign:
+ m_parseErrorMessage = "Unexpected token '='";
+ return JSValue();
+ case TokSemi:
+ m_parseErrorMessage = "Unexpected token ';'";
+ return JSValue();
+ case TokError:
+ default:
+ m_parseErrorMessage = "Could not parse statement";
+ return JSValue();
+ }
+ }
+ case StartParseStatementEndStatement: {
+ ASSERT(stateStack.isEmpty());
+ if (m_lexer.currentToken().type != TokRParen)
+ return JSValue();
+ if (m_lexer.next() == TokEnd)
+ return lastValue;
+ m_parseErrorMessage = "Unexpected content at end of JSON literal";
+ return JSValue();
+ }
+ default:
+ ASSERT_NOT_REACHED();
+ }
+ if (stateStack.isEmpty())
+ return lastValue;
+ state = stateStack.last();
+ stateStack.removeLast();
+ continue;
+ }
+}
+
+// Instantiate the two flavors of LiteralParser we need instead of putting most of this file in LiteralParser.h
+template class LiteralParser<LChar>;
+template class LiteralParser<UChar>;
+
+}
diff --git a/Source/JavaScriptCore/runtime/LiteralParser.h b/Source/JavaScriptCore/runtime/LiteralParser.h
new file mode 100644
index 000000000..abe3f95b7
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/LiteralParser.h
@@ -0,0 +1,166 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LiteralParser_h
+#define LiteralParser_h
+
+#include "Identifier.h"
+#include "JSGlobalObjectFunctions.h"
+#include "JSValue.h"
+#include "UString.h"
+
+namespace JSC {
+
+typedef enum { StrictJSON, NonStrictJSON, JSONP } ParserMode;
+
+enum JSONPPathEntryType {
+ JSONPPathEntryTypeDeclare, // var pathEntryName = JSON
+ JSONPPathEntryTypeDot, // <prior entries>.pathEntryName = JSON
+ JSONPPathEntryTypeLookup, // <prior entries>[pathIndex] = JSON
+ JSONPPathEntryTypeCall // <prior entries>(JSON)
+};
+
+enum ParserState { StartParseObject, StartParseArray, StartParseExpression,
+ StartParseStatement, StartParseStatementEndStatement,
+ DoParseObjectStartExpression, DoParseObjectEndExpression,
+ DoParseArrayStartExpression, DoParseArrayEndExpression };
+enum TokenType { TokLBracket, TokRBracket, TokLBrace, TokRBrace,
+ TokString, TokIdentifier, TokNumber, TokColon,
+ TokLParen, TokRParen, TokComma, TokTrue, TokFalse,
+ TokNull, TokEnd, TokDot, TokAssign, TokSemi, TokError };
+
+struct JSONPPathEntry {
+ JSONPPathEntryType m_type;
+ Identifier m_pathEntryName;
+ int m_pathIndex;
+};
+
+struct JSONPData {
+ Vector<JSONPPathEntry> m_path;
+ Strong<Unknown> m_value;
+};
+
+template <typename CharType>
+struct LiteralParserToken {
+ TokenType type;
+ const CharType* start;
+ const CharType* end;
+ UString stringBuffer;
+ union {
+ double numberToken;
+ struct {
+ union {
+ const LChar* stringToken8;
+ const UChar* stringToken16;
+ };
+ unsigned stringIs8Bit : 1;
+ unsigned stringLength : 31;
+ };
+ };
+};
+
+template <typename CharType>
+ALWAYS_INLINE void setParserTokenString(LiteralParserToken<CharType>&, const CharType* string);
+
+template <typename CharType>
+class LiteralParser {
+public:
+ LiteralParser(ExecState* exec, const CharType* characters, unsigned length, ParserMode mode)
+ : m_exec(exec)
+ , m_lexer(characters, length, mode)
+ , m_mode(mode)
+ {
+ }
+
+ UString getErrorMessage()
+ {
+ if (!m_lexer.getErrorMessage().isEmpty())
+ return String::format("JSON Parse error: %s", m_lexer.getErrorMessage().ascii().data()).impl();
+ if (!m_parseErrorMessage.isEmpty())
+ return String::format("JSON Parse error: %s", m_parseErrorMessage.ascii().data()).impl();
+ return "JSON Parse error: Unable to parse JSON string";
+ }
+
+ JSValue tryLiteralParse()
+ {
+ m_lexer.next();
+ JSValue result = parse(m_mode == StrictJSON ? StartParseExpression : StartParseStatement);
+ if (m_lexer.currentToken().type == TokSemi)
+ m_lexer.next();
+ if (m_lexer.currentToken().type != TokEnd)
+ return JSValue();
+ return result;
+ }
+
+ bool tryJSONPParse(Vector<JSONPData>&, bool needsFullSourceInfo);
+
+private:
+ class Lexer {
+ public:
+ Lexer(const CharType* characters, unsigned length, ParserMode mode)
+ : m_mode(mode)
+ , m_ptr(characters)
+ , m_end(characters + length)
+ {
+ }
+
+ TokenType next();
+
+ const LiteralParserToken<CharType>& currentToken()
+ {
+ return m_currentToken;
+ }
+
+ UString getErrorMessage() { return m_lexErrorMessage; }
+
+ private:
+ UString m_lexErrorMessage;
+ template <ParserMode mode> TokenType lex(LiteralParserToken<CharType>&);
+ ALWAYS_INLINE TokenType lexIdentifier(LiteralParserToken<CharType>&);
+ template <ParserMode mode, char terminator> ALWAYS_INLINE TokenType lexString(LiteralParserToken<CharType>&);
+ ALWAYS_INLINE TokenType lexNumber(LiteralParserToken<CharType>&);
+ LiteralParserToken<CharType> m_currentToken;
+ ParserMode m_mode;
+ const CharType* m_ptr;
+ const CharType* m_end;
+ };
+
+ class StackGuard;
+ JSValue parse(ParserState);
+
+ ExecState* m_exec;
+ typename LiteralParser<CharType>::Lexer m_lexer;
+ ParserMode m_mode;
+ UString m_parseErrorMessage;
+ static unsigned const MaximumCachableCharacter = 128;
+ FixedArray<Identifier, MaximumCachableCharacter> m_shortIdentifiers;
+ FixedArray<Identifier, MaximumCachableCharacter> m_recentIdentifiers;
+ ALWAYS_INLINE const Identifier makeIdentifier(const LChar* characters, size_t length);
+ ALWAYS_INLINE const Identifier makeIdentifier(const UChar* characters, size_t length);
+ };
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/Lookup.cpp b/Source/JavaScriptCore/runtime/Lookup.cpp
new file mode 100644
index 000000000..55c048fa3
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Lookup.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "Lookup.h"
+
+#include "Executable.h"
+#include "JSFunction.h"
+
+namespace JSC {
+
+void HashTable::createTable(JSGlobalData* globalData) const
+{
+ ASSERT(!table);
+ int linkIndex = compactHashSizeMask + 1;
+ HashEntry* entries = new HashEntry[compactSize];
+ for (int i = 0; i < compactSize; ++i)
+ entries[i].setKey(0);
+ for (int i = 0; values[i].key; ++i) {
+ StringImpl* identifier = Identifier::add(globalData, values[i].key).leakRef();
+ int hashIndex = identifier->existingHash() & compactHashSizeMask;
+ HashEntry* entry = &entries[hashIndex];
+
+ if (entry->key()) {
+ while (entry->next()) {
+ entry = entry->next();
+ }
+ ASSERT(linkIndex < compactSize);
+ entry->setNext(&entries[linkIndex++]);
+ entry = entry->next();
+ }
+
+ entry->initialize(identifier, values[i].attributes, values[i].value1, values[i].value2, values[i].intrinsic);
+ }
+ table = entries;
+}
+
+void HashTable::deleteTable() const
+{
+ if (table) {
+ int max = compactSize;
+ for (int i = 0; i != max; ++i) {
+ if (StringImpl* key = table[i].key())
+ key->deref();
+ }
+ delete [] table;
+ table = 0;
+ }
+}
+
+bool setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
+{
+ ASSERT(thisObj->globalObject());
+ ASSERT(entry->attributes() & Function);
+ WriteBarrierBase<Unknown>* location = thisObj->getDirectLocation(exec->globalData(), propertyName);
+
+ if (!location) {
+ // If a property is ever deleted from an object with a static table, then we reify
+ // all static functions at that time - after this we shouldn't be re-adding anything.
+ if (thisObj->staticFunctionsReified())
+ return false;
+
+ JSFunction* function;
+ JSGlobalObject* globalObject = thisObj->globalObject();
+#if ENABLE(JIT)
+ if (exec->globalData().canUseJIT() && entry->intrinsic() != NoIntrinsic)
+ function = JSFunction::create(exec, globalObject, entry->functionLength(), propertyName, exec->globalData().getHostFunction(entry->function(), entry->intrinsic()));
+ else
+#endif
+ function = JSFunction::create(exec, globalObject, entry->functionLength(), propertyName, entry->function());
+
+ thisObj->putDirect(exec->globalData(), propertyName, function, entry->attributes());
+ location = thisObj->getDirectLocation(exec->globalData(), propertyName);
+ }
+
+ slot.setValue(thisObj, location->get(), thisObj->offsetForLocation(location));
+ return true;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Lookup.h b/Source/JavaScriptCore/runtime/Lookup.h
new file mode 100644
index 000000000..8ed70b41d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Lookup.h
@@ -0,0 +1,384 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef Lookup_h
+#define Lookup_h
+
+#include "CallFrame.h"
+#include "Intrinsic.h"
+#include "Identifier.h"
+#include "JSGlobalObject.h"
+#include "PropertySlot.h"
+#include <stdio.h>
+#include <wtf/Assertions.h>
+
+namespace JSC {
+ // Hash table generated by the create_hash_table script.
+ struct HashTableValue {
+ const char* key; // property name
+ unsigned char attributes; // JSObject attributes
+ intptr_t value1;
+ intptr_t value2;
+ Intrinsic intrinsic;
+ };
+
+ // FIXME: There is no reason this get function can't be simpler.
+ // ie. typedef JSValue (*GetFunction)(ExecState*, JSObject* baseObject)
+ typedef PropertySlot::GetValueFunc GetFunction;
+ typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value);
+
+ class HashEntry {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ void initialize(StringImpl* key, unsigned char attributes, intptr_t v1, intptr_t v2, Intrinsic intrinsic)
+ {
+ m_key = key;
+ m_attributes = attributes;
+ m_u.store.value1 = v1;
+ m_u.store.value2 = v2;
+ m_u.function.intrinsic = intrinsic;
+ m_next = 0;
+ }
+
+ void setKey(StringImpl* key) { m_key = key; }
+ StringImpl* key() const { return m_key; }
+
+ unsigned char attributes() const { return m_attributes; }
+
+ Intrinsic intrinsic() const
+ {
+ ASSERT(m_attributes & Function);
+ return m_u.function.intrinsic;
+ }
+
+ NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
+ unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
+
+ GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
+ PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
+
+ intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
+
+ void setNext(HashEntry *next) { m_next = next; }
+ HashEntry* next() const { return m_next; }
+
+ private:
+ StringImpl* m_key;
+ unsigned char m_attributes; // JSObject attributes
+
+ union {
+ struct {
+ intptr_t value1;
+ intptr_t value2;
+ } store;
+ struct {
+ NativeFunction functionValue;
+ intptr_t length; // number of arguments for function
+ Intrinsic intrinsic;
+ } function;
+ struct {
+ GetFunction get;
+ PutFunction put;
+ } property;
+ struct {
+ intptr_t value;
+ intptr_t unused;
+ } lexer;
+ } m_u;
+
+ HashEntry* m_next;
+ };
+
+ struct HashTable {
+
+ int compactSize;
+ int compactHashSizeMask;
+
+ const HashTableValue* values; // Fixed values generated by script.
+ mutable const HashEntry* table; // Table allocated at runtime.
+
+ ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
+ {
+ if (!table)
+ createTable(globalData);
+ }
+
+ ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
+ {
+ if (!table)
+ createTable(&exec->globalData());
+ }
+
+ void deleteTable() const;
+
+ // Find an entry in the table, and return the entry.
+ ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
+ {
+ initializeIfNeeded(globalData);
+ return entry(identifier);
+ }
+
+ ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
+ {
+ initializeIfNeeded(exec);
+ return entry(identifier);
+ }
+
+ class ConstIterator {
+ public:
+ ConstIterator(const HashTable* table, int position)
+ : m_table(table)
+ , m_position(position)
+ {
+ skipInvalidKeys();
+ }
+
+ const HashEntry* operator->()
+ {
+ return &m_table->table[m_position];
+ }
+
+ const HashEntry* operator*()
+ {
+ return &m_table->table[m_position];
+ }
+
+ bool operator!=(const ConstIterator& other)
+ {
+ ASSERT(m_table == other.m_table);
+ return m_position != other.m_position;
+ }
+
+ ConstIterator& operator++()
+ {
+ ASSERT(m_position < m_table->compactSize);
+ ++m_position;
+ skipInvalidKeys();
+ return *this;
+ }
+
+ private:
+ void skipInvalidKeys()
+ {
+ ASSERT(m_position <= m_table->compactSize);
+ while (m_position < m_table->compactSize && !m_table->table[m_position].key())
+ ++m_position;
+ ASSERT(m_position <= m_table->compactSize);
+ }
+
+ const HashTable* m_table;
+ int m_position;
+ };
+
+ ConstIterator begin(JSGlobalData& globalData) const
+ {
+ initializeIfNeeded(&globalData);
+ return ConstIterator(this, 0);
+ }
+ ConstIterator end(JSGlobalData& globalData) const
+ {
+ initializeIfNeeded(&globalData);
+ return ConstIterator(this, compactSize);
+ }
+
+ private:
+ ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
+ {
+ ASSERT(table);
+
+ const HashEntry* entry = &table[identifier.impl()->existingHash() & compactHashSizeMask];
+
+ if (!entry->key())
+ return 0;
+
+ do {
+ if (entry->key() == identifier.impl())
+ return entry;
+ entry = entry->next();
+ } while (entry);
+
+ return 0;
+ }
+
+ // Convert the hash table keys to identifiers.
+ void createTable(JSGlobalData*) const;
+ };
+
+ bool setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
+
+ /**
+ * This method does it all (looking in the hashtable, checking for function
+ * overrides, creating the function or retrieving from cache, calling
+ * getValueProperty in case of a non-function property, forwarding to parent if
+ * unknown property).
+ */
+ template <class ThisImp, class ParentImp>
+ inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ {
+ const HashEntry* entry = table->entry(exec, propertyName);
+
+ if (!entry) // not found, forward to parent
+ return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
+
+ if (entry->attributes() & Function)
+ return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+
+ slot.setCacheableCustom(thisObj, entry->propertyGetter());
+ return true;
+ }
+
+ template <class ThisImp, class ParentImp>
+ inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
+ {
+ const HashEntry* entry = table->entry(exec, propertyName);
+
+ if (!entry) // not found, forward to parent
+ return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
+
+ PropertySlot slot;
+ if (entry->attributes() & Function) {
+ bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+ if (present)
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+ return present;
+ }
+
+ slot.setCustom(thisObj, entry->propertyGetter());
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+ return true;
+ }
+
+ /**
+ * Simplified version of getStaticPropertySlot in case there are only functions.
+ * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
+ * a dummy getValueProperty.
+ */
+ template <class ParentImp>
+ inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ {
+ if (ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot))
+ return true;
+
+ const HashEntry* entry = table->entry(exec, propertyName);
+ if (!entry)
+ return false;
+
+ return setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+ }
+
+ /**
+ * Simplified version of getStaticPropertyDescriptor in case there are only functions.
+ * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing
+ * a dummy getValueProperty.
+ */
+ template <class ParentImp>
+ inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
+ {
+ if (ParentImp::getOwnPropertyDescriptor(static_cast<ParentImp*>(thisObj), exec, propertyName, descriptor))
+ return true;
+
+ const HashEntry* entry = table->entry(exec, propertyName);
+ if (!entry)
+ return false;
+
+ PropertySlot slot;
+ bool present = setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+ if (present)
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+ return present;
+ }
+
+ /**
+ * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
+ * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
+ */
+ template <class ThisImp, class ParentImp>
+ inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ {
+ const HashEntry* entry = table->entry(exec, propertyName);
+
+ if (!entry) // not found, forward to parent
+ return ParentImp::getOwnPropertySlot(thisObj, exec, propertyName, slot);
+
+ ASSERT(!(entry->attributes() & Function));
+
+ slot.setCacheableCustom(thisObj, entry->propertyGetter());
+ return true;
+ }
+
+ /**
+ * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values".
+ * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class.
+ */
+ template <class ThisImp, class ParentImp>
+ inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor)
+ {
+ const HashEntry* entry = table->entry(exec, propertyName);
+
+ if (!entry) // not found, forward to parent
+ return ParentImp::getOwnPropertyDescriptor(thisObj, exec, propertyName, descriptor);
+
+ ASSERT(!(entry->attributes() & Function));
+ PropertySlot slot;
+ slot.setCustom(thisObj, entry->propertyGetter());
+ descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes());
+ return true;
+ }
+
+ /**
+ * This one is for "put".
+ * It looks up a hash entry for the property to be set. If an entry
+ * is found it sets the value and returns true, else it returns false.
+ */
+ template <class ThisImp>
+ inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, bool shouldThrow = false)
+ {
+ const HashEntry* entry = table->entry(exec, propertyName);
+
+ if (!entry)
+ return false;
+
+ // If this is a function put it as an override property.
+ if (entry->attributes() & Function)
+ thisObj->putDirect(exec->globalData(), propertyName, value);
+ else if (!(entry->attributes() & ReadOnly))
+ entry->propertyPutter()(exec, thisObj, value);
+ else if (shouldThrow)
+ throwTypeError(exec, StrictModeReadonlyPropertyWriteError);
+
+ return true;
+ }
+
+ /**
+ * This one is for "put".
+ * It calls lookupPut<ThisImp>() to set the value. If that call
+ * returns false (meaning no entry in the hash table was found),
+ * then it calls put() on the ParentImp class.
+ */
+ template <class ThisImp, class ParentImp>
+ inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
+ {
+ if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj, slot.isStrictMode()))
+ ParentImp::put(thisObj, exec, propertyName, value, slot); // not found: forward to parent
+ }
+
+} // namespace JSC
+
+#endif // Lookup_h
diff --git a/Source/JavaScriptCore/runtime/MathObject.cpp b/Source/JavaScriptCore/runtime/MathObject.cpp
new file mode 100644
index 000000000..58b09122d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MathObject.cpp
@@ -0,0 +1,246 @@
+/*
+ * 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 "Lookup.h"
+#include "ObjectPrototype.h"
+#include "Operations.h"
+#include <time.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/RandomNumber.h>
+#include <wtf/RandomNumberSeed.h>
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(MathObject);
+
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState*);
+static EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState*);
+
+}
+
+#include "MathObject.lut.h"
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(MathObject);
+
+const ClassInfo MathObject::s_info = { "Math", &JSNonFinalObject::s_info, 0, ExecState::mathTable, CREATE_METHOD_TABLE(MathObject) };
+
+/* 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(JSGlobalObject* globalObject, Structure* structure)
+ : JSNonFinalObject(globalObject->globalData(), structure)
+{
+}
+
+void MathObject::finishCreation(ExecState* exec, JSGlobalObject* globalObject)
+{
+ Base::finishCreation(globalObject->globalData());
+ ASSERT(inherits(&s_info));
+
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "E"), jsNumber(exp(1.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LN2"), jsNumber(log(2.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LN10"), jsNumber(log(10.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LOG2E"), jsNumber(1.0 / log(2.0)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "LOG10E"), jsNumber(0.4342944819032518), DontDelete | DontEnum | ReadOnly); // See ECMA-262 15.8.1.5
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "PI"), jsNumber(piDouble), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "SQRT1_2"), jsNumber(sqrt(0.5)), DontDelete | DontEnum | ReadOnly);
+ putDirectWithoutTransition(exec->globalData(), Identifier(exec, "SQRT2"), jsNumber(sqrt(2.0)), DontDelete | DontEnum | ReadOnly);
+}
+
+bool MathObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<JSObject>(exec, ExecState::mathTable(exec), jsCast<MathObject*>(cell), propertyName, slot);
+}
+
+bool MathObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<JSObject>(exec, ExecState::mathTable(exec), jsCast<MathObject*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Functions --------------------------------
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState* exec)
+{
+ return JSValue::encode(jsNumber(fabs(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncACos(ExecState* exec)
+{
+ return JSValue::encode(jsDoubleNumber(acos(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncASin(ExecState* exec)
+{
+ return JSValue::encode(jsDoubleNumber(asin(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncATan(ExecState* exec)
+{
+ return JSValue::encode(jsDoubleNumber(atan(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState* exec)
+{
+ double arg0 = exec->argument(0).toNumber(exec);
+ double arg1 = exec->argument(1).toNumber(exec);
+ return JSValue::encode(jsDoubleNumber(atan2(arg0, arg1)));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec)
+{
+ return JSValue::encode(jsNumber(ceil(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec)
+{
+ return JSValue::encode(jsDoubleNumber(cos(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncExp(ExecState* exec)
+{
+ return JSValue::encode(jsDoubleNumber(exp(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec)
+{
+ return JSValue::encode(jsNumber(floor(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec)
+{
+ return JSValue::encode(jsDoubleNumber(log(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec)
+{
+ unsigned argsCount = exec->argumentCount();
+ double result = -std::numeric_limits<double>::infinity();
+ for (unsigned k = 0; k < argsCount; ++k) {
+ double val = exec->argument(k).toNumber(exec);
+ if (isnan(val)) {
+ result = std::numeric_limits<double>::quiet_NaN();
+ break;
+ }
+ if (val > result || (val == 0 && result == 0 && !signbit(val)))
+ result = val;
+ }
+ return JSValue::encode(jsNumber(result));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncMin(ExecState* exec)
+{
+ unsigned argsCount = exec->argumentCount();
+ double result = +std::numeric_limits<double>::infinity();
+ for (unsigned k = 0; k < argsCount; ++k) {
+ double val = exec->argument(k).toNumber(exec);
+ if (isnan(val)) {
+ result = std::numeric_limits<double>::quiet_NaN();
+ break;
+ }
+ if (val < result || (val == 0 && result == 0 && signbit(val)))
+ result = val;
+ }
+ return JSValue::encode(jsNumber(result));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec)
+{
+ // ECMA 15.8.2.1.13
+
+ double arg = exec->argument(0).toNumber(exec);
+ double arg2 = exec->argument(1).toNumber(exec);
+
+ if (isnan(arg2))
+ return JSValue::encode(jsNaN());
+ if (isinf(arg2) && fabs(arg) == 1)
+ return JSValue::encode(jsNaN());
+ return JSValue::encode(jsNumber(pow(arg, arg2)));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec)
+{
+ return JSValue::encode(jsDoubleNumber(exec->lexicalGlobalObject()->weakRandomNumber()));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec)
+{
+ double arg = exec->argument(0).toNumber(exec);
+ double integer = ceil(arg);
+ return JSValue::encode(jsNumber(integer - (integer - arg > 0.5)));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec)
+{
+ return JSValue::encode(exec->globalData().cachedSin(exec->argument(0).toNumber(exec)));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec)
+{
+ return JSValue::encode(jsDoubleNumber(sqrt(exec->argument(0).toNumber(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec)
+{
+ return JSValue::encode(jsDoubleNumber(tan(exec->argument(0).toNumber(exec))));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/MathObject.h b/Source/JavaScriptCore/runtime/MathObject.h
new file mode 100644
index 000000000..d8da039d8
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MathObject.h
@@ -0,0 +1,58 @@
+/*
+ * 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 JSNonFinalObject {
+ private:
+ MathObject(JSGlobalObject*, Structure*);
+
+ public:
+ typedef JSNonFinalObject Base;
+
+ static MathObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ MathObject* object = new (NotNull, allocateCell<MathObject>(*exec->heap())) MathObject(globalObject, structure);
+ object->finishCreation(exec, globalObject);
+ return object;
+ }
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(ExecState*, JSGlobalObject*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags;
+ };
+
+} // namespace JSC
+
+#endif // MathObject_h
diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.cpp b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
new file mode 100644
index 000000000..86101f559
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MemoryStatistics.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "MemoryStatistics.h"
+
+#include "ExecutableAllocator.h"
+#include "JSGlobalData.h"
+#include "RegisterFile.h"
+
+namespace JSC {
+
+GlobalMemoryStatistics globalMemoryStatistics()
+{
+ GlobalMemoryStatistics stats;
+
+ stats.stackBytes = RegisterFile::committedByteCount();
+#if ENABLE(EXECUTABLE_ALLOCATOR_FIXED)
+ stats.JITBytes = ExecutableAllocator::committedByteCount();
+#else
+ stats.JITBytes = 0;
+#endif
+ return stats;
+}
+
+}
+
+
diff --git a/Source/JavaScriptCore/runtime/MemoryStatistics.h b/Source/JavaScriptCore/runtime/MemoryStatistics.h
new file mode 100644
index 000000000..d4b8b6fc1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/MemoryStatistics.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef MemoryStatistics_h
+#define MemoryStatistics_h
+
+#include "Heap.h"
+
+class JSGlobalData;
+
+namespace JSC {
+
+struct GlobalMemoryStatistics {
+ size_t stackBytes;
+ size_t JITBytes;
+};
+
+GlobalMemoryStatistics globalMemoryStatistics();
+
+}
+
+#endif // MemoryStatistics_h
+
diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp
new file mode 100644
index 000000000..b6aff916e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "NativeErrorConstructor.h"
+
+#include "ErrorInstance.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "NativeErrorPrototype.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(NativeErrorConstructor);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(NativeErrorConstructor);
+
+const ClassInfo NativeErrorConstructor::s_info = { "Function", &InternalFunction::s_info, 0, 0, CREATE_METHOD_TABLE(NativeErrorConstructor) };
+
+NativeErrorConstructor::NativeErrorConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void NativeErrorConstructor::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ NativeErrorConstructor* thisObject = jsCast<NativeErrorConstructor*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ InternalFunction::visitChildren(thisObject, visitor);
+ if (thisObject->m_errorStructure)
+ visitor.append(&thisObject->m_errorStructure);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWithNativeErrorConstructor(ExecState* exec)
+{
+ JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
+ Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure();
+ ASSERT(errorStructure);
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message));
+}
+
+ConstructType NativeErrorConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithNativeErrorConstructor;
+ return ConstructTypeHost;
+}
+
+static EncodedJSValue JSC_HOST_CALL callNativeErrorConstructor(ExecState* exec)
+{
+ JSValue message = exec->argumentCount() ? exec->argument(0) : jsUndefined();
+ Structure* errorStructure = static_cast<NativeErrorConstructor*>(exec->callee())->errorStructure();
+ return JSValue::encode(ErrorInstance::create(exec, errorStructure, message));
+}
+
+CallType NativeErrorConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callNativeErrorConstructor;
+ return CallTypeHost;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NativeErrorConstructor.h b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h
new file mode 100644
index 000000000..41e4235fa
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NativeErrorConstructor.h
@@ -0,0 +1,80 @@
+/*
+ * 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"
+#include "NativeErrorPrototype.h"
+
+namespace JSC {
+
+ class ErrorInstance;
+ class FunctionPrototype;
+ class NativeErrorPrototype;
+
+ class NativeErrorConstructor : public InternalFunction {
+ public:
+ typedef InternalFunction Base;
+
+ static NativeErrorConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, Structure* prototypeStructure, const UString& name)
+ {
+ NativeErrorConstructor* constructor = new (NotNull, allocateCell<NativeErrorConstructor>(*exec->heap())) NativeErrorConstructor(globalObject, structure);
+ constructor->finishCreation(exec, globalObject, prototypeStructure, name);
+ return constructor;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ Structure* errorStructure() { return m_errorStructure.get(); }
+
+ protected:
+ void finishCreation(ExecState* exec, JSGlobalObject* globalObject, Structure* prototypeStructure, const UString& name)
+ {
+ Base::finishCreation(exec->globalData(), Identifier(exec, name));
+ ASSERT(inherits(&s_info));
+
+ NativeErrorPrototype* prototype = NativeErrorPrototype::create(exec, globalObject, prototypeStructure, name, this);
+
+ putDirect(exec->globalData(), exec->propertyNames().length, jsNumber(1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5
+ putDirect(exec->globalData(), exec->propertyNames().prototype, prototype, DontDelete | ReadOnly | DontEnum);
+ m_errorStructure.set(exec->globalData(), this, ErrorInstance::createStructure(exec->globalData(), globalObject, prototype));
+ ASSERT(m_errorStructure);
+ ASSERT(m_errorStructure->isObject());
+ }
+
+ private:
+ NativeErrorConstructor(JSGlobalObject*, Structure*);
+ static const unsigned StructureFlags = OverridesVisitChildren | InternalFunction::StructureFlags;
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ WriteBarrier<Structure> m_errorStructure;
+ };
+
+} // namespace JSC
+
+#endif // NativeErrorConstructor_h
diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp
new file mode 100644
index 000000000..dfdd87f85
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.cpp
@@ -0,0 +1,46 @@
+/*
+ * 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 "JSGlobalObject.h"
+#include "JSString.h"
+#include "NativeErrorConstructor.h"
+#include "UString.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(NativeErrorPrototype);
+
+NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, Structure* structure)
+ : ErrorPrototype(exec, structure)
+{
+}
+
+void NativeErrorPrototype::finishCreation(ExecState* exec, JSGlobalObject* globalObject, const UString& nameAndMessage, NativeErrorConstructor* constructor)
+{
+ Base::finishCreation(exec, globalObject);
+ putDirect(exec->globalData(), exec->propertyNames().name, jsString(exec, nameAndMessage), DontEnum);
+ putDirect(exec->globalData(), exec->propertyNames().message, jsEmptyString(exec), DontEnum);
+ putDirect(exec->globalData(), exec->propertyNames().constructor, constructor, DontEnum);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NativeErrorPrototype.h b/Source/JavaScriptCore/runtime/NativeErrorPrototype.h
new file mode 100644
index 000000000..4bceb883a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NativeErrorPrototype.h
@@ -0,0 +1,49 @@
+/*
+ * 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 "ErrorPrototype.h"
+
+namespace JSC {
+ class NativeErrorConstructor;
+
+ class NativeErrorPrototype : public ErrorPrototype {
+ private:
+ NativeErrorPrototype(ExecState*, Structure*);
+
+ public:
+ typedef ErrorPrototype Base;
+
+ static NativeErrorPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, const UString& name, NativeErrorConstructor* constructor)
+ {
+ NativeErrorPrototype* prototype = new (NotNull, allocateCell<NativeErrorPrototype>(*exec->heap())) NativeErrorPrototype(exec, structure);
+ prototype->finishCreation(exec, globalObject, name, constructor);
+ return prototype;
+ }
+
+ protected:
+ void finishCreation(ExecState*, JSGlobalObject*, const UString& nameAndMessage, NativeErrorConstructor*);
+ };
+
+} // namespace JSC
+
+#endif // NativeErrorPrototype_h
diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.cpp b/Source/JavaScriptCore/runtime/NumberConstructor.cpp
new file mode 100644
index 000000000..e1ff62f32
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NumberConstructor.cpp
@@ -0,0 +1,143 @@
+/*
+ * Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
+ * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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 "Lookup.h"
+#include "NumberObject.h"
+#include "NumberPrototype.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(NumberConstructor);
+
+static JSValue numberConstructorNaNValue(ExecState*, JSValue, const Identifier&);
+static JSValue numberConstructorNegInfinity(ExecState*, JSValue, const Identifier&);
+static JSValue numberConstructorPosInfinity(ExecState*, JSValue, const Identifier&);
+static JSValue numberConstructorMaxValue(ExecState*, JSValue, const Identifier&);
+static JSValue numberConstructorMinValue(ExecState*, JSValue, const Identifier&);
+
+} // namespace JSC
+
+#include "NumberConstructor.lut.h"
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberConstructor);
+
+const ClassInfo NumberConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::numberConstructorTable, CREATE_METHOD_TABLE(NumberConstructor) };
+
+/* Source for NumberConstructor.lut.h
+@begin numberConstructorTable
+ NaN numberConstructorNaNValue DontEnum|DontDelete|ReadOnly
+ NEGATIVE_INFINITY numberConstructorNegInfinity DontEnum|DontDelete|ReadOnly
+ POSITIVE_INFINITY numberConstructorPosInfinity DontEnum|DontDelete|ReadOnly
+ MAX_VALUE numberConstructorMaxValue DontEnum|DontDelete|ReadOnly
+ MIN_VALUE numberConstructorMinValue DontEnum|DontDelete|ReadOnly
+@end
+*/
+
+NumberConstructor::NumberConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void NumberConstructor::finishCreation(ExecState* exec, NumberPrototype* numberPrototype)
+{
+ Base::finishCreation(exec->globalData(), Identifier(exec, numberPrototype->s_info.className));
+ ASSERT(inherits(&s_info));
+
+ // Number.Prototype
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, numberPrototype, DontEnum | DontDelete | ReadOnly);
+
+ // no. of arguments for constructor
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+}
+
+bool NumberConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticValueSlot<NumberConstructor, InternalFunction>(exec, ExecState::numberConstructorTable(exec), jsCast<NumberConstructor*>(cell), propertyName, slot);
+}
+
+bool NumberConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticValueDescriptor<NumberConstructor, InternalFunction>(exec, ExecState::numberConstructorTable(exec), jsCast<NumberConstructor*>(object), propertyName, descriptor);
+}
+
+void NumberConstructor::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ lookupPut<NumberConstructor, InternalFunction>(exec, propertyName, value, ExecState::numberConstructorTable(exec), jsCast<NumberConstructor*>(cell), slot);
+}
+
+static JSValue numberConstructorNaNValue(ExecState*, JSValue, const Identifier&)
+{
+ return jsNaN();
+}
+
+static JSValue numberConstructorNegInfinity(ExecState*, JSValue, const Identifier&)
+{
+ return jsNumber(-std::numeric_limits<double>::infinity());
+}
+
+static JSValue numberConstructorPosInfinity(ExecState*, JSValue, const Identifier&)
+{
+ return jsNumber(std::numeric_limits<double>::infinity());
+}
+
+static JSValue numberConstructorMaxValue(ExecState*, JSValue, const Identifier&)
+{
+ return jsNumber(1.7976931348623157E+308);
+}
+
+static JSValue numberConstructorMinValue(ExecState*, JSValue, const Identifier&)
+{
+ return jsNumber(5E-324);
+}
+
+// ECMA 15.7.1
+static EncodedJSValue JSC_HOST_CALL constructWithNumberConstructor(ExecState* exec)
+{
+ NumberObject* object = NumberObject::create(exec->globalData(), asInternalFunction(exec->callee())->globalObject()->numberObjectStructure());
+ double n = exec->argumentCount() ? exec->argument(0).toNumber(exec) : 0;
+ object->setInternalValue(exec->globalData(), jsNumber(n));
+ return JSValue::encode(object);
+}
+
+ConstructType NumberConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithNumberConstructor;
+ return ConstructTypeHost;
+}
+
+// ECMA 15.7.2
+static EncodedJSValue JSC_HOST_CALL callNumberConstructor(ExecState* exec)
+{
+ return JSValue::encode(jsNumber(!exec->argumentCount() ? 0 : exec->argument(0).toNumber(exec)));
+}
+
+CallType NumberConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callNumberConstructor;
+ return CallTypeHost;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NumberConstructor.h b/Source/JavaScriptCore/runtime/NumberConstructor.h
new file mode 100644
index 000000000..4ee5b0716
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NumberConstructor.h
@@ -0,0 +1,68 @@
+/*
+ * 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:
+ typedef InternalFunction Base;
+
+ static NumberConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, NumberPrototype* numberPrototype)
+ {
+ NumberConstructor* constructor = new (NotNull, allocateCell<NumberConstructor>(*exec->heap())) NumberConstructor(globalObject, structure);
+ constructor->finishCreation(exec, numberPrototype);
+ return constructor;
+ }
+
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ JSValue getValueProperty(ExecState*, int token) const;
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto)
+ {
+ return Structure::create(globalData, globalObject, proto, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue };
+
+ protected:
+ void finishCreation(ExecState*, NumberPrototype*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | InternalFunction::StructureFlags;
+
+ private:
+ NumberConstructor(JSGlobalObject*, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ };
+
+} // namespace JSC
+
+#endif // NumberConstructor_h
diff --git a/Source/JavaScriptCore/runtime/NumberObject.cpp b/Source/JavaScriptCore/runtime/NumberObject.cpp
new file mode 100644
index 000000000..1fea25464
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NumberObject.cpp
@@ -0,0 +1,53 @@
+/*
+ * 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);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberObject);
+
+const ClassInfo NumberObject::s_info = { "Number", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(NumberObject) };
+
+NumberObject::NumberObject(JSGlobalData& globalData, Structure* structure)
+ : JSWrapperObject(globalData, structure)
+{
+}
+
+void NumberObject::finishCreation(JSGlobalData& globalData)
+{
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+}
+
+NumberObject* constructNumber(ExecState* exec, JSGlobalObject* globalObject, JSValue number)
+{
+ NumberObject* object = NumberObject::create(exec->globalData(), globalObject->numberObjectStructure());
+ object->setInternalValue(exec->globalData(), number);
+ return object;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NumberObject.h b/Source/JavaScriptCore/runtime/NumberObject.h
new file mode 100644
index 000000000..07334722b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NumberObject.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 NumberObject_h
+#define NumberObject_h
+
+#include "JSWrapperObject.h"
+
+namespace JSC {
+
+ class NumberObject : public JSWrapperObject {
+ protected:
+ NumberObject(JSGlobalData&, Structure*);
+ void finishCreation(JSGlobalData&);
+
+ public:
+ typedef JSWrapperObject Base;
+
+ static NumberObject* create(JSGlobalData& globalData, Structure* structure)
+ {
+ NumberObject* number = new (NotNull, allocateCell<NumberObject>(globalData.heap)) NumberObject(globalData, structure);
+ number->finishCreation(globalData);
+ return number;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), &s_info);
+ }
+ };
+
+ NumberObject* constructNumber(ExecState*, JSGlobalObject*, JSValue);
+
+} // namespace JSC
+
+#endif // NumberObject_h
diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.cpp b/Source/JavaScriptCore/runtime/NumberPrototype.cpp
new file mode 100644
index 000000000..4612b56d2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NumberPrototype.cpp
@@ -0,0 +1,488 @@
+/*
+ * Copyright (C) 1999-2000,2003 Harri Porten (porten@kde.org)
+ * Copyright (C) 2007, 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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 "BigInteger.h"
+#include "Error.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "JSString.h"
+#include "Operations.h"
+#include "Uint16WithFraction.h"
+#include "dtoa.h"
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/Vector.h>
+#include <wtf/dtoa/double-conversion.h>
+
+using namespace WTF::double_conversion;
+
+// To avoid conflict with WTF::StringBuilder.
+typedef WTF::double_conversion::StringBuilder DoubleConversionStringBuilder;
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState*);
+static EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*);
+
+}
+
+#include "NumberPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo NumberPrototype::s_info = { "Number", &NumberObject::s_info, 0, ExecState::numberPrototypeTable, CREATE_METHOD_TABLE(NumberPrototype) };
+
+/* Source for NumberPrototype.lut.h
+@begin numberPrototypeTable
+ toString numberProtoFuncToString DontEnum|Function 1
+ toLocaleString numberProtoFuncToLocaleString DontEnum|Function 0
+ valueOf numberProtoFuncValueOf DontEnum|Function 0
+ toFixed numberProtoFuncToFixed DontEnum|Function 1
+ toExponential numberProtoFuncToExponential DontEnum|Function 1
+ toPrecision numberProtoFuncToPrecision DontEnum|Function 1
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(NumberPrototype);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(NumberPrototype);
+
+NumberPrototype::NumberPrototype(ExecState* exec, Structure* structure)
+ : NumberObject(exec->globalData(), structure)
+{
+}
+
+void NumberPrototype::finishCreation(ExecState* exec, JSGlobalObject*)
+{
+ Base::finishCreation(exec->globalData());
+ setInternalValue(exec->globalData(), jsNumber(0));
+
+ ASSERT(inherits(&s_info));
+}
+
+bool NumberPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<NumberObject>(exec, ExecState::numberPrototypeTable(exec), jsCast<NumberPrototype*>(cell), propertyName, slot);
+}
+
+bool NumberPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<NumberObject>(exec, ExecState::numberPrototypeTable(exec), jsCast<NumberPrototype*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Functions ---------------------------
+
+static ALWAYS_INLINE bool toThisNumber(JSValue thisValue, double& x)
+{
+ if (thisValue.isInt32()) {
+ x = thisValue.asInt32();
+ return true;
+ }
+
+ if (thisValue.isDouble()) {
+ x = thisValue.asDouble();
+ return true;
+ }
+
+ if (thisValue.isCell() && thisValue.asCell()->structure()->typeInfo().isNumberObject()) {
+ x = static_cast<const NumberObject*>(thisValue.asCell())->internalValue().asNumber();
+ return true;
+ }
+
+ return false;
+}
+
+static ALWAYS_INLINE bool getIntegerArgumentInRange(ExecState* exec, int low, int high, int& result, bool& isUndefined)
+{
+ result = 0;
+ isUndefined = false;
+
+ JSValue argument0 = exec->argument(0);
+ if (argument0.isUndefined()) {
+ isUndefined = true;
+ return true;
+ }
+
+ double asDouble = argument0.toInteger(exec);
+ if (asDouble < low || asDouble > high)
+ return false;
+
+ result = static_cast<int>(asDouble);
+ return true;
+}
+
+// The largest finite floating point number is 1.mantissa * 2^(0x7fe-0x3ff).
+// Since 2^N in binary is a one bit followed by N zero bits. 1 * 2^3ff requires
+// at most 1024 characters to the left of a decimal point, in base 2 (1025 if
+// we include a minus sign). For the fraction, a value with an exponent of 0
+// has up to 52 bits to the right of the decimal point. Each decrement of the
+// exponent down to a minimum of -0x3fe adds an additional digit to the length
+// of the fraction. As such the maximum fraction size is 1075 (1076 including
+// a point). We pick a buffer size such that can simply place the point in the
+// center of the buffer, and are guaranteed to have enough space in each direction
+// fo any number of digits an IEEE number may require to represent.
+typedef char RadixBuffer[2180];
+
+// Mapping from integers 0..35 to digit identifying this value, for radix 2..36.
+static const char* const radixDigits = "0123456789abcdefghijklmnopqrstuvwxyz";
+
+static char* toStringWithRadix(RadixBuffer& buffer, double number, unsigned radix)
+{
+ ASSERT(isfinite(number));
+ ASSERT(radix >= 2 && radix <= 36);
+
+ // Position the decimal point at the center of the string, set
+ // the startOfResultString pointer to point at the decimal point.
+ char* decimalPoint = buffer + sizeof(buffer) / 2;
+ char* startOfResultString = decimalPoint;
+
+ // Extract the sign.
+ bool isNegative = number < 0;
+ if (signbit(number))
+ number = -number;
+ double integerPart = floor(number);
+
+ // We use this to test for odd values in odd radix bases.
+ // Where the base is even, (e.g. 10), to determine whether a value is even we need only
+ // consider the least significant digit. For example, 124 in base 10 is even, because '4'
+ // is even. if the radix is odd, then the radix raised to an integer power is also odd.
+ // E.g. in base 5, 124 represents (1 * 125 + 2 * 25 + 4 * 5). Since each digit in the value
+ // is multiplied by an odd number, the result is even if the sum of all digits is even.
+ //
+ // For the integer portion of the result, we only need test whether the integer value is
+ // even or odd. For each digit of the fraction added, we should invert our idea of whether
+ // the number is odd if the new digit is odd.
+ //
+ // Also initialize digit to this value; for even radix values we only need track whether
+ // the last individual digit was odd.
+ bool integerPartIsOdd = integerPart <= static_cast<double>(0x1FFFFFFFFFFFFFull) && static_cast<int64_t>(integerPart) & 1;
+ ASSERT(integerPartIsOdd == static_cast<bool>(fmod(integerPart, 2)));
+ bool isOddInOddRadix = integerPartIsOdd;
+ uint32_t digit = integerPartIsOdd;
+
+ // Check if the value has a fractional part to convert.
+ double fractionPart = number - integerPart;
+ if (fractionPart) {
+ // Write the decimal point now.
+ *decimalPoint = '.';
+
+ // Higher precision representation of the fractional part.
+ Uint16WithFraction fraction(fractionPart);
+
+ bool needsRoundingUp = false;
+ char* endOfResultString = decimalPoint + 1;
+
+ // Calculate the delta from the current number to the next & previous possible IEEE numbers.
+ double nextNumber = nextafter(number, std::numeric_limits<double>::infinity());
+ double lastNumber = nextafter(number, -std::numeric_limits<double>::infinity());
+ ASSERT(isfinite(nextNumber) && !signbit(nextNumber));
+ ASSERT(isfinite(lastNumber) && !signbit(lastNumber));
+ double deltaNextDouble = nextNumber - number;
+ double deltaLastDouble = number - lastNumber;
+ ASSERT(isfinite(deltaNextDouble) && !signbit(deltaNextDouble));
+ ASSERT(isfinite(deltaLastDouble) && !signbit(deltaLastDouble));
+
+ // We track the delta from the current value to the next, to track how many digits of the
+ // fraction we need to write. For example, if the value we are converting is precisely
+ // 1.2345, so far we have written the digits "1.23" to a string leaving a remainder of
+ // 0.45, and we want to determine whether we can round off, or whether we need to keep
+ // appending digits ('4'). We can stop adding digits provided that then next possible
+ // lower IEEE value is further from 1.23 than the remainder we'd be rounding off (0.45),
+ // which is to say, less than 1.2255. Put another way, the delta between the prior
+ // possible value and this number must be more than 2x the remainder we'd be rounding off
+ // (or more simply half the delta between numbers must be greater than the remainder).
+ //
+ // Similarly we need track the delta to the next possible value, to dertermine whether
+ // to round up. In almost all cases (other than at exponent boundaries) the deltas to
+ // prior and subsequent values are identical, so we don't need track then separately.
+ if (deltaNextDouble != deltaLastDouble) {
+ // Since the deltas are different track them separately. Pre-multiply by 0.5.
+ Uint16WithFraction halfDeltaNext(deltaNextDouble, 1);
+ Uint16WithFraction halfDeltaLast(deltaLastDouble, 1);
+
+ while (true) {
+ // examine the remainder to determine whether we should be considering rounding
+ // up or down. If remainder is precisely 0.5 rounding is to even.
+ int dComparePoint5 = fraction.comparePoint5();
+ if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
+ // Check for rounding up; are we closer to the value we'd round off to than
+ // the next IEEE value would be?
+ if (fraction.sumGreaterThanOne(halfDeltaNext)) {
+ needsRoundingUp = true;
+ break;
+ }
+ } else {
+ // Check for rounding down; are we closer to the value we'd round off to than
+ // the prior IEEE value would be?
+ if (fraction < halfDeltaLast)
+ break;
+ }
+
+ ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
+ // Write a digit to the string.
+ fraction *= radix;
+ digit = fraction.floorAndSubtract();
+ *endOfResultString++ = radixDigits[digit];
+ // Keep track whether the portion written is currently even, if the radix is odd.
+ if (digit & 1)
+ isOddInOddRadix = !isOddInOddRadix;
+
+ // Shift the fractions by radix.
+ halfDeltaNext *= radix;
+ halfDeltaLast *= radix;
+ }
+ } else {
+ // This code is identical to that above, except since deltaNextDouble != deltaLastDouble
+ // we don't need to track these two values separately.
+ Uint16WithFraction halfDelta(deltaNextDouble, 1);
+
+ while (true) {
+ int dComparePoint5 = fraction.comparePoint5();
+ if (dComparePoint5 > 0 || (!dComparePoint5 && (radix & 1 ? isOddInOddRadix : digit & 1))) {
+ if (fraction.sumGreaterThanOne(halfDelta)) {
+ needsRoundingUp = true;
+ break;
+ }
+ } else if (fraction < halfDelta)
+ break;
+
+ ASSERT(endOfResultString < (buffer + sizeof(buffer) - 1));
+ fraction *= radix;
+ digit = fraction.floorAndSubtract();
+ if (digit & 1)
+ isOddInOddRadix = !isOddInOddRadix;
+ *endOfResultString++ = radixDigits[digit];
+
+ halfDelta *= radix;
+ }
+ }
+
+ // Check if the fraction needs rounding off (flag set in the loop writing digits, above).
+ if (needsRoundingUp) {
+ // Whilst the last digit is the maximum in the current radix, remove it.
+ // e.g. rounding up the last digit in "12.3999" is the same as rounding up the
+ // last digit in "12.3" - both round up to "12.4".
+ while (endOfResultString[-1] == radixDigits[radix - 1])
+ --endOfResultString;
+
+ // Radix digits are sequential in ascii/unicode, except for '9' and 'a'.
+ // E.g. the first 'if' case handles rounding 67.89 to 67.8a in base 16.
+ // The 'else if' case handles rounding of all other digits.
+ if (endOfResultString[-1] == '9')
+ endOfResultString[-1] = 'a';
+ else if (endOfResultString[-1] != '.')
+ ++endOfResultString[-1];
+ else {
+ // One other possibility - there may be no digits to round up in the fraction
+ // (or all may be been rounded off already), in which case we may need to
+ // round into the integer portion of the number. Remove the decimal point.
+ --endOfResultString;
+ // In order to get here there must have been a non-zero fraction, in which case
+ // there must be at least one bit of the value's mantissa not in use in the
+ // integer part of the number. As such, adding to the integer part should not
+ // be able to lose precision.
+ ASSERT((integerPart + 1) - integerPart == 1);
+ ++integerPart;
+ }
+ } else {
+ // We only need to check for trailing zeros if the value does not get rounded up.
+ while (endOfResultString[-1] == '0')
+ --endOfResultString;
+ }
+
+ *endOfResultString = '\0';
+ ASSERT(endOfResultString < buffer + sizeof(buffer));
+ } else
+ *decimalPoint = '\0';
+
+ BigInteger units(integerPart);
+
+ // Always loop at least once, to emit at least '0'.
+ do {
+ ASSERT(buffer < startOfResultString);
+
+ // Read a single digit and write it to the front of the string.
+ // Divide by radix to remove one digit from the value.
+ digit = units.divide(radix);
+ *--startOfResultString = radixDigits[digit];
+ } while (!!units);
+
+ // If the number is negative, prepend '-'.
+ if (isNegative)
+ *--startOfResultString = '-';
+ ASSERT(buffer <= startOfResultString);
+
+ return startOfResultString;
+}
+
+// toExponential converts a number to a string, always formatting as an expoential.
+// This method takes an optional argument specifying a number of *decimal places*
+// to round the significand to (or, put another way, this method optionally rounds
+// to argument-plus-one significant figures).
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToExponential(ExecState* exec)
+{
+ double x;
+ if (!toThisNumber(exec->hostThisValue(), x))
+ return throwVMTypeError(exec);
+
+ // Get the argument.
+ int decimalPlacesInExponent;
+ bool isUndefined;
+ if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlacesInExponent, isUndefined))
+ return throwVMError(exec, createRangeError(exec, "toExponential() argument must be between 0 and 20"));
+
+ // Handle NaN and Infinity.
+ if (!isfinite(x))
+ return JSValue::encode(jsString(exec, UString::number(x)));
+
+ // Round if the argument is not undefined, always format as exponential.
+ char buffer[WTF::NumberToStringBufferLength];
+ DoubleConversionStringBuilder builder(buffer, WTF::NumberToStringBufferLength);
+ const DoubleToStringConverter& converter = DoubleToStringConverter::EcmaScriptConverter();
+ builder.Reset();
+ isUndefined
+ ? converter.ToExponential(x, -1, &builder)
+ : converter.ToExponential(x, decimalPlacesInExponent, &builder);
+ return JSValue::encode(jsString(exec, UString(builder.Finalize())));
+}
+
+// toFixed converts a number to a string, always formatting as an a decimal fraction.
+// This method takes an argument specifying a number of decimal places to round the
+// significand to. However when converting large values (1e+21 and above) this
+// method will instead fallback to calling ToString.
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToFixed(ExecState* exec)
+{
+ double x;
+ if (!toThisNumber(exec->hostThisValue(), x))
+ return throwVMTypeError(exec);
+
+ // Get the argument.
+ int decimalPlaces;
+ bool isUndefined; // This is ignored; undefined treated as 0.
+ if (!getIntegerArgumentInRange(exec, 0, 20, decimalPlaces, isUndefined))
+ return throwVMError(exec, createRangeError(exec, "toFixed() argument must be between 0 and 20"));
+
+ // 15.7.4.5.7 states "If x >= 10^21, then let m = ToString(x)"
+ // This also covers Ininity, and structure the check so that NaN
+ // values are also handled by numberToString
+ if (!(fabs(x) < 1e+21))
+ return JSValue::encode(jsString(exec, UString::number(x)));
+
+ // The check above will return false for NaN or Infinity, these will be
+ // handled by numberToString.
+ ASSERT(isfinite(x));
+
+ NumberToStringBuffer buffer;
+ return JSValue::encode(jsString(exec, UString(numberToFixedWidthString(x, decimalPlaces, buffer))));
+}
+
+// toPrecision converts a number to a string, takeing an argument specifying a
+// number of significant figures to round the significand to. For positive
+// exponent, all values that can be represented using a decimal fraction will
+// be, e.g. when rounding to 3 s.f. any value up to 999 will be formated as a
+// decimal, whilst 1000 is converted to the exponential representation 1.00e+3.
+// For negative exponents values >= 1e-6 are formated as decimal fractions,
+// with smaller values converted to exponential representation.
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState* exec)
+{
+ double x;
+ if (!toThisNumber(exec->hostThisValue(), x))
+ return throwVMTypeError(exec);
+
+ // Get the argument.
+ int significantFigures;
+ bool isUndefined;
+ if (!getIntegerArgumentInRange(exec, 1, 21, significantFigures, isUndefined))
+ return throwVMError(exec, createRangeError(exec, "toPrecision() argument must be between 1 and 21"));
+
+ // To precision called with no argument is treated as ToString.
+ if (isUndefined)
+ return JSValue::encode(jsString(exec, UString::number(x)));
+
+ // Handle NaN and Infinity.
+ if (!isfinite(x))
+ return JSValue::encode(jsString(exec, UString::number(x)));
+
+ NumberToStringBuffer buffer;
+ return JSValue::encode(jsString(exec, UString(numberToFixedPrecisionString(x, significantFigures, buffer))));
+}
+
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToString(ExecState* exec)
+{
+ double x;
+ if (!toThisNumber(exec->hostThisValue(), x))
+ return throwVMTypeError(exec);
+
+ JSValue radixValue = exec->argument(0);
+ int radix;
+ if (radixValue.isInt32())
+ radix = radixValue.asInt32();
+ else if (radixValue.isUndefined())
+ radix = 10;
+ else
+ radix = static_cast<int>(radixValue.toInteger(exec)); // nan -> 0
+
+ if (radix == 10)
+ return JSValue::encode(jsString(exec, jsNumber(x).toString(exec)));
+
+ // Fast path for number to character conversion.
+ if (radix == 36) {
+ unsigned c = static_cast<unsigned>(x);
+ if (c == x && c < 36) {
+ JSGlobalData* globalData = &exec->globalData();
+ return JSValue::encode(globalData->smallStrings.singleCharacterString(globalData, radixDigits[c]));
+ }
+ }
+
+ if (radix < 2 || radix > 36)
+ return throwVMError(exec, createRangeError(exec, "toString() radix argument must be between 2 and 36"));
+
+ if (!isfinite(x))
+ return JSValue::encode(jsString(exec, UString::number(x)));
+
+ RadixBuffer s;
+ return JSValue::encode(jsString(exec, toStringWithRadix(s, x, radix)));
+}
+
+EncodedJSValue JSC_HOST_CALL numberProtoFuncToLocaleString(ExecState* exec)
+{
+ double x;
+ if (!toThisNumber(exec->hostThisValue(), x))
+ return throwVMTypeError(exec);
+
+ return JSValue::encode(jsString(exec, jsNumber(x).toString(exec)));
+}
+
+EncodedJSValue JSC_HOST_CALL numberProtoFuncValueOf(ExecState* exec)
+{
+ double x;
+ if (!toThisNumber(exec->hostThisValue(), x))
+ return throwVMTypeError(exec);
+ return JSValue::encode(jsNumber(x));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/NumberPrototype.h b/Source/JavaScriptCore/runtime/NumberPrototype.h
new file mode 100644
index 000000000..d63cc3a6f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NumberPrototype.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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:
+ typedef NumberObject Base;
+
+ static NumberPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ NumberPrototype* prototype = new (NotNull, allocateCell<NumberPrototype>(*exec->heap())) NumberPrototype(exec, structure);
+ prototype->finishCreation(exec, globalObject);
+ return prototype;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(NumberObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(ExecState*, JSGlobalObject*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NumberObject::StructureFlags;
+
+ private:
+ NumberPrototype(ExecState*, Structure*);
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ };
+
+} // namespace JSC
+
+#endif // NumberPrototype_h
diff --git a/Source/JavaScriptCore/runtime/NumericStrings.h b/Source/JavaScriptCore/runtime/NumericStrings.h
new file mode 100644
index 000000000..d65f14265
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/NumericStrings.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef NumericStrings_h
+#define NumericStrings_h
+
+#include "UString.h"
+#include <wtf/FixedArray.h>
+#include <wtf/HashFunctions.h>
+
+namespace JSC {
+
+ class NumericStrings {
+ public:
+ UString add(double d)
+ {
+ CacheEntry<double>& entry = lookup(d);
+ if (d == entry.key && !entry.value.isNull())
+ return entry.value;
+ entry.key = d;
+ entry.value = UString::number(d);
+ return entry.value;
+ }
+
+ UString add(int i)
+ {
+ if (static_cast<unsigned>(i) < cacheSize)
+ return lookupSmallString(static_cast<unsigned>(i));
+ CacheEntry<int>& entry = lookup(i);
+ if (i == entry.key && !entry.value.isNull())
+ return entry.value;
+ entry.key = i;
+ entry.value = UString::number(i);
+ return entry.value;
+ }
+
+ UString add(unsigned i)
+ {
+ if (i < cacheSize)
+ return lookupSmallString(static_cast<unsigned>(i));
+ CacheEntry<unsigned>& entry = lookup(i);
+ if (i == entry.key && !entry.value.isNull())
+ return entry.value;
+ entry.key = i;
+ entry.value = UString::number(i);
+ return entry.value;
+ }
+ private:
+ static const size_t cacheSize = 64;
+
+ template<typename T>
+ struct CacheEntry {
+ T key;
+ UString value;
+ };
+
+ CacheEntry<double>& lookup(double d) { return doubleCache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; }
+ CacheEntry<int>& lookup(int i) { return intCache[WTF::IntHash<int>::hash(i) & (cacheSize - 1)]; }
+ CacheEntry<unsigned>& lookup(unsigned i) { return unsignedCache[WTF::IntHash<unsigned>::hash(i) & (cacheSize - 1)]; }
+ const UString& lookupSmallString(unsigned i)
+ {
+ ASSERT(i < cacheSize);
+ if (smallIntCache[i].isNull())
+ smallIntCache[i] = UString::number(i);
+ return smallIntCache[i];
+ }
+
+ FixedArray<CacheEntry<double>, cacheSize> doubleCache;
+ FixedArray<CacheEntry<int>, cacheSize> intCache;
+ FixedArray<CacheEntry<unsigned>, cacheSize> unsignedCache;
+ FixedArray<UString, cacheSize> smallIntCache;
+ };
+
+} // namespace JSC
+
+#endif // NumericStrings_h
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.cpp b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
new file mode 100644
index 000000000..65d28c18c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.cpp
@@ -0,0 +1,415 @@
+/*
+ * 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 "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSFunction.h"
+#include "JSArray.h"
+#include "JSGlobalObject.h"
+#include "Lookup.h"
+#include "ObjectPrototype.h"
+#include "PropertyDescriptor.h"
+#include "PropertyNameArray.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor);
+
+static EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState*);
+
+}
+
+#include "ObjectConstructor.lut.h"
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(ObjectConstructor);
+
+const ClassInfo ObjectConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::objectConstructorTable, CREATE_METHOD_TABLE(ObjectConstructor) };
+
+/* Source for ObjectConstructor.lut.h
+@begin objectConstructorTable
+ getPrototypeOf objectConstructorGetPrototypeOf DontEnum|Function 1
+ getOwnPropertyDescriptor objectConstructorGetOwnPropertyDescriptor DontEnum|Function 2
+ getOwnPropertyNames objectConstructorGetOwnPropertyNames DontEnum|Function 1
+ keys objectConstructorKeys DontEnum|Function 1
+ defineProperty objectConstructorDefineProperty DontEnum|Function 3
+ defineProperties objectConstructorDefineProperties DontEnum|Function 2
+ create objectConstructorCreate DontEnum|Function 2
+ seal objectConstructorSeal DontEnum|Function 1
+ freeze objectConstructorFreeze DontEnum|Function 1
+ preventExtensions objectConstructorPreventExtensions DontEnum|Function 1
+ isSealed objectConstructorIsSealed DontEnum|Function 1
+ isFrozen objectConstructorIsFrozen DontEnum|Function 1
+ isExtensible objectConstructorIsExtensible DontEnum|Function 1
+@end
+*/
+
+ObjectConstructor::ObjectConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void ObjectConstructor::finishCreation(ExecState* exec, ObjectPrototype* objectPrototype)
+{
+ Base::finishCreation(exec->globalData(), Identifier(exec, "Object"));
+ // ECMA 15.2.3.1
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, objectPrototype, DontEnum | DontDelete | ReadOnly);
+ // no. of arguments for constructor
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+}
+
+bool ObjectConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<JSObject>(exec, ExecState::objectConstructorTable(exec), jsCast<ObjectConstructor*>(cell), propertyName, slot);
+}
+
+bool ObjectConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<JSObject>(exec, ExecState::objectConstructorTable(exec), jsCast<ObjectConstructor*>(object), propertyName, descriptor);
+}
+
+// ECMA 15.2.2
+static ALWAYS_INLINE JSObject* constructObject(ExecState* exec, JSGlobalObject* globalObject, const ArgList& args)
+{
+ JSValue arg = args.at(0);
+ if (arg.isUndefinedOrNull())
+ return constructEmptyObject(exec, globalObject);
+ return arg.toObject(exec, globalObject);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWithObjectConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args));
+}
+
+ConstructType ObjectConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithObjectConstructor;
+ return ConstructTypeHost;
+}
+
+static EncodedJSValue JSC_HOST_CALL callObjectConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructObject(exec, asInternalFunction(exec->callee())->globalObject(), args));
+}
+
+CallType ObjectConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callObjectConstructor;
+ return CallTypeHost;
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec)
+{
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Requested prototype of a value that is not an object."));
+
+ // This uses JSValue::get() instead of directly accessing the prototype from the object
+ // (using JSObject::prototype()) in order to allow objects to override the behavior, such
+ // as returning jsUndefined() for cross-origin access.
+ return JSValue::encode(exec->argument(0).get(exec, exec->propertyNames().underscoreProto));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec)
+{
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Requested property descriptor of a value that is not an object."));
+ UString propertyName = exec->argument(1).toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ JSObject* object = asObject(exec->argument(0));
+ PropertyDescriptor descriptor;
+ if (!object->methodTable()->getOwnPropertyDescriptor(object, exec, Identifier(exec, propertyName), descriptor))
+ return JSValue::encode(jsUndefined());
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ JSObject* description = constructEmptyObject(exec);
+ if (!descriptor.isAccessorDescriptor()) {
+ description->putDirect(exec->globalData(), exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0);
+ description->putDirect(exec->globalData(), exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0);
+ } else {
+ description->putDirect(exec->globalData(), exec->propertyNames().get, descriptor.getter() ? descriptor.getter() : jsUndefined(), 0);
+ description->putDirect(exec->globalData(), exec->propertyNames().set, descriptor.setter() ? descriptor.setter() : jsUndefined(), 0);
+ }
+
+ description->putDirect(exec->globalData(), exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0);
+ description->putDirect(exec->globalData(), exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0);
+
+ return JSValue::encode(description);
+}
+
+// FIXME: Use the enumeration cache.
+EncodedJSValue JSC_HOST_CALL objectConstructorGetOwnPropertyNames(ExecState* exec)
+{
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Requested property names of a value that is not an object."));
+ PropertyNameArray properties(exec);
+ asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, IncludeDontEnumProperties);
+ JSArray* names = constructEmptyArray(exec);
+ size_t numProperties = properties.size();
+ for (size_t i = 0; i < numProperties; i++)
+ names->push(exec, jsOwnedString(exec, properties[i].ustring()));
+ return JSValue::encode(names);
+}
+
+// FIXME: Use the enumeration cache.
+EncodedJSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec)
+{
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Requested keys of a value that is not an object."));
+ PropertyNameArray properties(exec);
+ asObject(exec->argument(0))->methodTable()->getOwnPropertyNames(asObject(exec->argument(0)), exec, properties, ExcludeDontEnumProperties);
+ JSArray* keys = constructEmptyArray(exec);
+ size_t numProperties = properties.size();
+ for (size_t i = 0; i < numProperties; i++)
+ keys->push(exec, jsOwnedString(exec, properties[i].ustring()));
+ return JSValue::encode(keys);
+}
+
+// ES5 8.10.5 ToPropertyDescriptor
+static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc)
+{
+ if (!in.isObject()) {
+ throwError(exec, createTypeError(exec, "Property description must be an object."));
+ return false;
+ }
+ JSObject* description = asObject(in);
+
+ PropertySlot enumerableSlot(description);
+ if (description->getPropertySlot(exec, exec->propertyNames().enumerable, enumerableSlot)) {
+ desc.setEnumerable(enumerableSlot.getValue(exec, exec->propertyNames().enumerable).toBoolean(exec));
+ if (exec->hadException())
+ return false;
+ }
+
+ PropertySlot configurableSlot(description);
+ if (description->getPropertySlot(exec, exec->propertyNames().configurable, configurableSlot)) {
+ desc.setConfigurable(configurableSlot.getValue(exec, exec->propertyNames().configurable).toBoolean(exec));
+ if (exec->hadException())
+ return false;
+ }
+
+ JSValue value;
+ PropertySlot valueSlot(description);
+ if (description->getPropertySlot(exec, exec->propertyNames().value, valueSlot)) {
+ desc.setValue(valueSlot.getValue(exec, exec->propertyNames().value));
+ if (exec->hadException())
+ return false;
+ }
+
+ PropertySlot writableSlot(description);
+ if (description->getPropertySlot(exec, exec->propertyNames().writable, writableSlot)) {
+ desc.setWritable(writableSlot.getValue(exec, exec->propertyNames().writable).toBoolean(exec));
+ if (exec->hadException())
+ return false;
+ }
+
+ PropertySlot getSlot(description);
+ if (description->getPropertySlot(exec, exec->propertyNames().get, getSlot)) {
+ JSValue get = getSlot.getValue(exec, exec->propertyNames().get);
+ if (exec->hadException())
+ return false;
+ if (!get.isUndefined()) {
+ CallData callData;
+ if (getCallData(get, callData) == CallTypeNone) {
+ throwError(exec, createTypeError(exec, "Getter must be a function."));
+ return false;
+ }
+ } else
+ get = JSValue();
+ desc.setGetter(get);
+ }
+
+ PropertySlot setSlot(description);
+ if (description->getPropertySlot(exec, exec->propertyNames().set, setSlot)) {
+ JSValue set = setSlot.getValue(exec, exec->propertyNames().set);
+ if (exec->hadException())
+ return false;
+ if (!set.isUndefined()) {
+ CallData callData;
+ if (getCallData(set, callData) == CallTypeNone) {
+ throwError(exec, createTypeError(exec, "Setter must be a function."));
+ return false;
+ }
+ } else
+ set = JSValue();
+
+ desc.setSetter(set);
+ }
+
+ if (!desc.isAccessorDescriptor())
+ return true;
+
+ if (desc.value()) {
+ throwError(exec, createTypeError(exec, "Invalid property. 'value' present on property with getter or setter."));
+ return false;
+ }
+
+ if (desc.writablePresent()) {
+ throwError(exec, createTypeError(exec, "Invalid property. 'writable' present on property with getter or setter."));
+ return false;
+ }
+ return true;
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec)
+{
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Properties can only be defined on Objects."));
+ JSObject* O = asObject(exec->argument(0));
+ UString propertyName = exec->argument(1).toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ PropertyDescriptor descriptor;
+ if (!toPropertyDescriptor(exec, exec->argument(2), descriptor))
+ return JSValue::encode(jsNull());
+ ASSERT((descriptor.attributes() & (Getter | Setter)) || (!descriptor.isAccessorDescriptor()));
+ ASSERT(!exec->hadException());
+ O->methodTable()->defineOwnProperty(O, exec, Identifier(exec, propertyName), descriptor, true);
+ return JSValue::encode(O);
+}
+
+static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties)
+{
+ PropertyNameArray propertyNames(exec);
+ asObject(properties)->methodTable()->getOwnPropertyNames(asObject(properties), exec, propertyNames, ExcludeDontEnumProperties);
+ size_t numProperties = propertyNames.size();
+ Vector<PropertyDescriptor> descriptors;
+ MarkedArgumentBuffer markBuffer;
+ for (size_t i = 0; i < numProperties; i++) {
+ PropertySlot slot;
+ JSValue prop = properties->get(exec, propertyNames[i]);
+ if (exec->hadException())
+ return jsNull();
+ PropertyDescriptor descriptor;
+ if (!toPropertyDescriptor(exec, prop, descriptor))
+ return jsNull();
+ descriptors.append(descriptor);
+ // Ensure we mark all the values that we're accumulating
+ if (descriptor.isDataDescriptor() && descriptor.value())
+ markBuffer.append(descriptor.value());
+ if (descriptor.isAccessorDescriptor()) {
+ if (descriptor.getter())
+ markBuffer.append(descriptor.getter());
+ if (descriptor.setter())
+ markBuffer.append(descriptor.setter());
+ }
+ }
+ for (size_t i = 0; i < numProperties; i++) {
+ object->methodTable()->defineOwnProperty(object, exec, propertyNames[i], descriptors[i], true);
+ if (exec->hadException())
+ return jsNull();
+ }
+ return object;
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState* exec)
+{
+ if (!exec->argument(0).isObject())
+ return throwVMError(exec, createTypeError(exec, "Properties can only be defined on Objects."));
+ if (!exec->argument(1).isObject())
+ return throwVMError(exec, createTypeError(exec, "Property descriptor list must be an Object."));
+ return JSValue::encode(defineProperties(exec, asObject(exec->argument(0)), asObject(exec->argument(1))));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec)
+{
+ if (!exec->argument(0).isObject() && !exec->argument(0).isNull())
+ return throwVMError(exec, createTypeError(exec, "Object prototype may only be an Object or null."));
+ JSValue proto = exec->argument(0);
+ JSObject* newObject = proto.isObject() ? constructEmptyObject(exec, asObject(proto)->inheritorID(exec->globalData())) : constructEmptyObject(exec, exec->lexicalGlobalObject()->nullPrototypeObjectStructure());
+ if (exec->argument(1).isUndefined())
+ return JSValue::encode(newObject);
+ if (!exec->argument(1).isObject())
+ return throwVMError(exec, createTypeError(exec, "Property descriptor list must be an Object."));
+ return JSValue::encode(defineProperties(exec, newObject, asObject(exec->argument(1))));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorSeal(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.seal can only be called on Objects."));
+ asObject(obj)->seal(exec->globalData());
+ return JSValue::encode(obj);
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorFreeze(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.freeze can only be called on Objects."));
+ asObject(obj)->freeze(exec->globalData());
+ return JSValue::encode(obj);
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorPreventExtensions(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.preventExtensions can only be called on Objects."));
+ asObject(obj)->preventExtensions(exec->globalData());
+ return JSValue::encode(obj);
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorIsSealed(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.isSealed can only be called on Objects."));
+ return JSValue::encode(jsBoolean(asObject(obj)->isSealed(exec->globalData())));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorIsFrozen(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.isFrozen can only be called on Objects."));
+ return JSValue::encode(jsBoolean(asObject(obj)->isFrozen(exec->globalData())));
+}
+
+EncodedJSValue JSC_HOST_CALL objectConstructorIsExtensible(ExecState* exec)
+{
+ JSValue obj = exec->argument(0);
+ if (!obj.isObject())
+ return throwVMError(exec, createTypeError(exec, "Object.isExtensible can only be called on Objects."));
+ return JSValue::encode(jsBoolean(asObject(obj)->isExtensible()));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ObjectConstructor.h b/Source/JavaScriptCore/runtime/ObjectConstructor.h
new file mode 100644
index 000000000..87c6414c4
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ObjectConstructor.h
@@ -0,0 +1,63 @@
+/*
+ * 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:
+ typedef InternalFunction Base;
+
+ static ObjectConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, ObjectPrototype* objectPrototype)
+ {
+ ObjectConstructor* constructor = new (NotNull, allocateCell<ObjectConstructor>(*exec->heap())) ObjectConstructor(globalObject, structure);
+ constructor->finishCreation(exec, objectPrototype);
+ return constructor;
+ }
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(ExecState*, ObjectPrototype*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+
+ private:
+ ObjectConstructor(JSGlobalObject*, Structure*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+ };
+
+} // namespace JSC
+
+#endif // ObjectConstructor_h
diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.cpp b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
new file mode 100644
index 000000000..3f4dc19db
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ObjectPrototype.cpp
@@ -0,0 +1,223 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "ObjectPrototype.h"
+
+#include "Error.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*);
+static EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*);
+
+}
+
+#include "ObjectPrototype.lut.h"
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(ObjectPrototype);
+
+const ClassInfo ObjectPrototype::s_info = { "Object", &JSNonFinalObject::s_info, 0, ExecState::objectPrototypeTable, CREATE_METHOD_TABLE(ObjectPrototype) };
+
+/* Source for ObjectPrototype.lut.h
+@begin objectPrototypeTable
+ toString objectProtoFuncToString DontEnum|Function 0
+ toLocaleString objectProtoFuncToLocaleString DontEnum|Function 0
+ valueOf objectProtoFuncValueOf DontEnum|Function 0
+ hasOwnProperty objectProtoFuncHasOwnProperty DontEnum|Function 1
+ propertyIsEnumerable objectProtoFuncPropertyIsEnumerable DontEnum|Function 1
+ isPrototypeOf objectProtoFuncIsPrototypeOf DontEnum|Function 1
+ __defineGetter__ objectProtoFuncDefineGetter DontEnum|Function 2
+ __defineSetter__ objectProtoFuncDefineSetter DontEnum|Function 2
+ __lookupGetter__ objectProtoFuncLookupGetter DontEnum|Function 1
+ __lookupSetter__ objectProtoFuncLookupSetter DontEnum|Function 1
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(ObjectPrototype);
+
+ObjectPrototype::ObjectPrototype(ExecState* exec, Structure* stucture)
+ : JSNonFinalObject(exec->globalData(), stucture)
+ , m_hasNoPropertiesWithUInt32Names(true)
+{
+}
+
+void ObjectPrototype::finishCreation(JSGlobalData& globalData, JSGlobalObject*)
+{
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+}
+
+void ObjectPrototype::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ ObjectPrototype* thisObject = jsCast<ObjectPrototype*>(cell);
+ JSNonFinalObject::put(cell, exec, propertyName, value, slot);
+
+ if (thisObject->m_hasNoPropertiesWithUInt32Names) {
+ bool isUInt32;
+ propertyName.toUInt32(isUInt32);
+ thisObject->m_hasNoPropertiesWithUInt32Names = !isUInt32;
+ }
+}
+
+bool ObjectPrototype::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ ObjectPrototype* thisObject = jsCast<ObjectPrototype*>(cell);
+ if (thisObject->m_hasNoPropertiesWithUInt32Names)
+ return false;
+ return JSNonFinalObject::getOwnPropertySlotByIndex(thisObject, exec, propertyName, slot);
+}
+
+bool ObjectPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<JSNonFinalObject>(exec, ExecState::objectPrototypeTable(exec), jsCast<ObjectPrototype*>(cell), propertyName, slot);
+}
+
+bool ObjectPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<JSNonFinalObject>(exec, ExecState::objectPrototypeTable(exec), jsCast<ObjectPrototype*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Functions --------------------------------
+
+EncodedJSValue JSC_HOST_CALL objectProtoFuncValueOf(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(thisValue.toObject(exec));
+}
+
+EncodedJSValue JSC_HOST_CALL objectProtoFuncHasOwnProperty(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(jsBoolean(thisValue.toObject(exec)->hasOwnProperty(exec, Identifier(exec, exec->argument(0).toString(exec)))));
+}
+
+EncodedJSValue JSC_HOST_CALL objectProtoFuncIsPrototypeOf(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ JSObject* thisObj = thisValue.toObject(exec);
+
+ if (!exec->argument(0).isObject())
+ return JSValue::encode(jsBoolean(false));
+
+ JSValue v = asObject(exec->argument(0))->prototype();
+
+ while (true) {
+ if (!v.isObject())
+ return JSValue::encode(jsBoolean(false));
+ if (v == thisObj)
+ return JSValue::encode(jsBoolean(true));
+ v = asObject(v)->prototype();
+ }
+}
+
+EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineGetter(ExecState* exec)
+{
+ JSObject* thisObject = exec->hostThisValue().toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData callData;
+ if (getCallData(exec->argument(1), callData) == CallTypeNone)
+ return throwVMError(exec, createSyntaxError(exec, "invalid getter usage"));
+ thisObject->methodTable()->defineGetter(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)), asObject(exec->argument(1)), 0);
+ return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL objectProtoFuncDefineSetter(ExecState* exec)
+{
+ JSObject* thisObject = exec->hostThisValue().toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ CallData callData;
+ if (getCallData(exec->argument(1), callData) == CallTypeNone)
+ return throwVMError(exec, createSyntaxError(exec, "invalid setter usage"));
+ thisObject->methodTable()->defineSetter(thisObject, exec, Identifier(exec, exec->argument(0).toString(exec)), asObject(exec->argument(1)), 0);
+ return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupGetter(ExecState* exec)
+{
+ JSObject* thisObject = exec->hostThisValue().toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(thisObject->lookupGetter(exec, Identifier(exec, exec->argument(0).toString(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState* exec)
+{
+ JSObject* thisObject = exec->hostThisValue().toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ return JSValue::encode(thisObject->lookupSetter(exec, Identifier(exec, exec->argument(0).toString(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(jsBoolean(thisValue.toObject(exec)->propertyIsEnumerable(exec, Identifier(exec, exec->argument(0).toString(exec)))));
+}
+
+// 15.2.4.3 Object.prototype.toLocaleString()
+EncodedJSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState* exec)
+{
+ // 1. Let O be the result of calling ToObject passing the this value as the argument.
+ JSObject* object = exec->hostThisValue().toObject(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ // 2. Let toString be the result of calling the [[Get]] internal method of O passing "toString" as the argument.
+ JSValue toString = object->get(exec, exec->propertyNames().toString);
+
+ // 3. If IsCallable(toString) is false, throw a TypeError exception.
+ CallData callData;
+ CallType callType = getCallData(toString, callData);
+ if (callType == CallTypeNone)
+ return JSValue::encode(jsUndefined());
+
+ // 4. Return the result of calling the [[Call]] internal method of toString passing O as the this value and no arguments.
+ return JSValue::encode(call(exec, toString, callType, callData, object, exec->emptyList()));
+}
+
+EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull())
+ return JSValue::encode(jsNontrivialString(exec, thisValue.isUndefined() ? "[object Undefined]" : "[object Null]"));
+ JSObject* thisObject = thisValue.toObject(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "[object ", thisObject->methodTable()->className(thisObject), "]"));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ObjectPrototype.h b/Source/JavaScriptCore/runtime/ObjectPrototype.h
new file mode 100644
index 000000000..78b1cbd39
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ObjectPrototype.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2008, 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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 JSNonFinalObject {
+ public:
+ typedef JSNonFinalObject Base;
+
+ static ObjectPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ ObjectPrototype* prototype = new (NotNull, allocateCell<ObjectPrototype>(*exec->heap())) ObjectPrototype(exec, structure);
+ prototype->finishCreation(exec->globalData(), globalObject);
+ return prototype;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSNonFinalObject::StructureFlags;
+
+ void finishCreation(JSGlobalData&, JSGlobalObject*);
+
+ private:
+ ObjectPrototype(ExecState*, Structure*);
+ static void put(JSCell*, ExecState*, const Identifier&, JSValue, PutPropertySlot&);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ bool m_hasNoPropertiesWithUInt32Names;
+ };
+
+ EncodedJSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*);
+
+} // namespace JSC
+
+#endif // ObjectPrototype_h
diff --git a/Source/JavaScriptCore/runtime/Operations.cpp b/Source/JavaScriptCore/runtime/Operations.cpp
new file mode 100644
index 000000000..b89746f3f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Operations.cpp
@@ -0,0 +1,114 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "Operations.h"
+
+#include "Error.h"
+#include "JSObject.h"
+#include "JSString.h"
+#include <math.h>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+namespace JSC {
+
+bool JSValue::equalSlowCase(ExecState* exec, JSValue v1, JSValue v2)
+{
+ return equalSlowCaseInline(exec, v1, v2);
+}
+
+bool JSValue::strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2)
+{
+ return strictEqualSlowCaseInline(exec, v1, v2);
+}
+
+NEVER_INLINE JSValue jsAddSlowCase(CallFrame* callFrame, JSValue v1, JSValue v2)
+{
+ // exception for the Date exception in defaultValue()
+ JSValue p1 = v1.toPrimitive(callFrame);
+ JSValue p2 = v2.toPrimitive(callFrame);
+
+ if (p1.isString()) {
+ return p2.isString()
+ ? jsString(callFrame, asString(p1), asString(p2))
+ : jsString(callFrame, asString(p1), jsString(callFrame, p2.toString(callFrame)));
+ }
+ if (p2.isString())
+ return jsString(callFrame, jsString(callFrame, p1.toString(callFrame)), asString(p2));
+
+ return jsNumber(p1.toNumber(callFrame) + p2.toNumber(callFrame));
+}
+
+JSValue jsTypeStringForValue(CallFrame* callFrame, JSValue v)
+{
+ if (v.isUndefined())
+ return jsNontrivialString(callFrame, "undefined");
+ if (v.isBoolean())
+ return jsNontrivialString(callFrame, "boolean");
+ if (v.isNumber())
+ return jsNontrivialString(callFrame, "number");
+ if (v.isString())
+ return jsNontrivialString(callFrame, "string");
+ if (v.isObject()) {
+ // Return "undefined" for objects that should be treated
+ // as null when doing comparisons.
+ if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined())
+ return jsNontrivialString(callFrame, "undefined");
+ CallData callData;
+ JSObject* object = asObject(v);
+ if (object->methodTable()->getCallData(object, callData) != CallTypeNone)
+ return jsNontrivialString(callFrame, "function");
+ }
+ return jsNontrivialString(callFrame, "object");
+}
+
+bool jsIsObjectType(JSValue v)
+{
+ if (!v.isCell())
+ return v.isNull();
+
+ JSType type = v.asCell()->structure()->typeInfo().type();
+ if (type == NumberType || type == StringType)
+ return false;
+ if (type >= ObjectType) {
+ if (asObject(v)->structure()->typeInfo().masqueradesAsUndefined())
+ return false;
+ CallData callData;
+ JSObject* object = asObject(v);
+ if (object->methodTable()->getCallData(object, callData) != CallTypeNone)
+ return false;
+ }
+ return true;
+}
+
+bool jsIsFunctionType(JSValue v)
+{
+ if (v.isObject()) {
+ CallData callData;
+ JSObject* object = asObject(v);
+ if (object->methodTable()->getCallData(object, callData) != CallTypeNone)
+ return true;
+ }
+ return false;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Operations.h b/Source/JavaScriptCore/runtime/Operations.h
new file mode 100644
index 000000000..ca2174fa1
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Operations.h
@@ -0,0 +1,392 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2002, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef Operations_h
+#define Operations_h
+
+#include "ExceptionHelpers.h"
+#include "Interpreter.h"
+#include "JSString.h"
+#include "JSValueInlineMethods.h"
+
+namespace JSC {
+
+ NEVER_INLINE JSValue jsAddSlowCase(CallFrame*, JSValue, JSValue);
+ JSValue jsTypeStringForValue(CallFrame*, JSValue);
+ bool jsIsObjectType(JSValue);
+ bool jsIsFunctionType(JSValue);
+
+ ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2)
+ {
+ JSGlobalData& globalData = exec->globalData();
+
+ unsigned length1 = s1->length();
+ if (!length1)
+ return s2;
+ unsigned length2 = s2->length();
+ if (!length2)
+ return s1;
+ if ((length1 + length2) < length1)
+ return throwOutOfMemoryError(exec);
+
+ return JSString::create(globalData, s1, s2);
+ }
+
+ ALWAYS_INLINE JSValue jsString(ExecState* exec, const UString& u1, const UString& u2, const UString& u3)
+ {
+ JSGlobalData* globalData = &exec->globalData();
+
+ unsigned length1 = u1.length();
+ unsigned length2 = u2.length();
+ unsigned length3 = u3.length();
+ if (!length1)
+ return jsString(exec, jsString(globalData, u2), jsString(globalData, u3));
+ if (!length2)
+ return jsString(exec, jsString(globalData, u1), jsString(globalData, u3));
+ if (!length3)
+ return jsString(exec, jsString(globalData, u1), jsString(globalData, u2));
+
+ if ((length1 + length2) < length1)
+ return throwOutOfMemoryError(exec);
+ if ((length1 + length2 + length3) < length3)
+ return throwOutOfMemoryError(exec);
+
+ return JSString::create(exec->globalData(), jsString(globalData, u1), jsString(globalData, u2), jsString(globalData, u3));
+ }
+
+ ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count)
+ {
+ JSGlobalData* globalData = &exec->globalData();
+ JSString::RopeBuilder ropeBuilder(*globalData);
+
+ unsigned oldLength = 0;
+
+ for (unsigned i = 0; i < count; ++i) {
+ JSValue v = strings[i].jsValue();
+ if (v.isString())
+ ropeBuilder.append(asString(v));
+ else
+ ropeBuilder.append(jsString(globalData, v.toString(exec)));
+
+ if (ropeBuilder.length() < oldLength) // True for overflow
+ return throwOutOfMemoryError(exec);
+ }
+
+ return ropeBuilder.release();
+ }
+
+ ALWAYS_INLINE JSValue jsStringFromArguments(ExecState* exec, JSValue thisValue)
+ {
+ JSGlobalData* globalData = &exec->globalData();
+ JSString::RopeBuilder ropeBuilder(*globalData);
+
+ if (thisValue.isString())
+ ropeBuilder.append(asString(thisValue));
+ else
+ ropeBuilder.append(jsString(globalData, thisValue.toString(exec)));
+
+ unsigned oldLength = 0;
+
+ for (unsigned i = 0; i < exec->argumentCount(); ++i) {
+ JSValue v = exec->argument(i);
+ if (v.isString())
+ ropeBuilder.append(asString(v));
+ else
+ ropeBuilder.append(jsString(globalData, v.toString(exec)));
+
+ if (ropeBuilder.length() < oldLength) // True for overflow
+ return throwOutOfMemoryError(exec);
+ }
+
+ return ropeBuilder.release();
+ }
+
+ // ECMA 11.9.3
+ inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2)
+ {
+ if (v1.isInt32() && v2.isInt32())
+ return v1 == v2;
+
+ return equalSlowCase(exec, v1, v2);
+ }
+
+ ALWAYS_INLINE bool JSValue::equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
+ {
+ do {
+ if (v1.isNumber() && v2.isNumber())
+ return v1.asNumber() == v2.asNumber();
+
+ bool s1 = v1.isString();
+ bool s2 = v2.isString();
+ if (s1 && s2)
+ return asString(v1)->value(exec) == asString(v2)->value(exec);
+
+ if (v1.isUndefinedOrNull()) {
+ if (v2.isUndefinedOrNull())
+ return true;
+ if (!v2.isCell())
+ return false;
+ return v2.asCell()->structure()->typeInfo().masqueradesAsUndefined();
+ }
+
+ if (v2.isUndefinedOrNull()) {
+ if (!v1.isCell())
+ return false;
+ return v1.asCell()->structure()->typeInfo().masqueradesAsUndefined();
+ }
+
+ if (v1.isObject()) {
+ if (v2.isObject())
+ return v1 == v2;
+ JSValue p1 = v1.toPrimitive(exec);
+ if (exec->hadException())
+ return false;
+ v1 = p1;
+ if (v1.isInt32() && v2.isInt32())
+ return v1 == v2;
+ continue;
+ }
+
+ if (v2.isObject()) {
+ JSValue p2 = v2.toPrimitive(exec);
+ if (exec->hadException())
+ return false;
+ v2 = p2;
+ if (v1.isInt32() && v2.isInt32())
+ return v1 == v2;
+ continue;
+ }
+
+ if (s1 || s2) {
+ double d1 = v1.toNumber(exec);
+ double d2 = v2.toNumber(exec);
+ return d1 == d2;
+ }
+
+ if (v1.isBoolean()) {
+ if (v2.isNumber())
+ return static_cast<double>(v1.asBoolean()) == v2.asNumber();
+ } else if (v2.isBoolean()) {
+ if (v1.isNumber())
+ return v1.asNumber() == static_cast<double>(v2.asBoolean());
+ }
+
+ return v1 == v2;
+ } while (true);
+ }
+
+ // ECMA 11.9.3
+ ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2)
+ {
+ ASSERT(v1.isCell() && v2.isCell());
+
+ if (v1.asCell()->isString() && v2.asCell()->isString())
+ return asString(v1)->value(exec) == asString(v2)->value(exec);
+
+ return v1 == v2;
+ }
+
+ inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2)
+ {
+ if (v1.isInt32() && v2.isInt32())
+ return v1 == v2;
+
+ if (v1.isNumber() && v2.isNumber())
+ return v1.asNumber() == v2.asNumber();
+
+ if (!v1.isCell() || !v2.isCell())
+ return v1 == v2;
+
+ return strictEqualSlowCaseInline(exec, v1, v2);
+ }
+
+ // See ES5 11.8.1/11.8.2/11.8.5 for definition of leftFirst, this value ensures correct
+ // evaluation ordering for argument conversions for '<' and '>'. For '<' pass the value
+ // true, for leftFirst, for '>' pass the value false (and reverse operand order).
+ template<bool leftFirst>
+ ALWAYS_INLINE bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2)
+ {
+ if (v1.isInt32() && v2.isInt32())
+ return v1.asInt32() < v2.asInt32();
+
+ if (v1.isNumber() && v2.isNumber())
+ return v1.asNumber() < v2.asNumber();
+
+ if (isJSString(v1) && isJSString(v2))
+ return asString(v1)->value(callFrame) < asString(v2)->value(callFrame);
+
+ double n1;
+ double n2;
+ JSValue p1;
+ JSValue p2;
+ bool wasNotString1;
+ bool wasNotString2;
+ if (leftFirst) {
+ wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
+ wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
+ } else {
+ wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
+ wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
+ }
+
+ if (wasNotString1 | wasNotString2)
+ return n1 < n2;
+ return asString(p1)->value(callFrame) < asString(p2)->value(callFrame);
+ }
+
+ // See ES5 11.8.3/11.8.4/11.8.5 for definition of leftFirst, this value ensures correct
+ // evaluation ordering for argument conversions for '<=' and '=>'. For '<=' pass the
+ // value true, for leftFirst, for '=>' pass the value false (and reverse operand order).
+ template<bool leftFirst>
+ ALWAYS_INLINE bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2)
+ {
+ if (v1.isInt32() && v2.isInt32())
+ return v1.asInt32() <= v2.asInt32();
+
+ if (v1.isNumber() && v2.isNumber())
+ return v1.asNumber() <= v2.asNumber();
+
+ if (isJSString(v1) && isJSString(v2))
+ return !(asString(v2)->value(callFrame) < asString(v1)->value(callFrame));
+
+ double n1;
+ double n2;
+ JSValue p1;
+ JSValue p2;
+ bool wasNotString1;
+ bool wasNotString2;
+ if (leftFirst) {
+ wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
+ wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
+ } else {
+ wasNotString2 = v2.getPrimitiveNumber(callFrame, n2, p2);
+ wasNotString1 = v1.getPrimitiveNumber(callFrame, n1, p1);
+ }
+
+ if (wasNotString1 | wasNotString2)
+ return n1 <= n2;
+ return !(asString(p2)->value(callFrame) < asString(p1)->value(callFrame));
+ }
+
+ // Fast-path choices here are based on frequency data from SunSpider:
+ // <times> Add case: <t1> <t2>
+ // ---------------------------
+ // 5626160 Add case: 3 3 (of these, 3637690 are for immediate values)
+ // 247412 Add case: 5 5
+ // 20900 Add case: 5 6
+ // 13962 Add case: 5 3
+ // 4000 Add case: 3 5
+
+ ALWAYS_INLINE JSValue jsAdd(CallFrame* callFrame, JSValue v1, JSValue v2)
+ {
+ if (v1.isNumber() && v2.isNumber())
+ return jsNumber(v1.asNumber() + v2.asNumber());
+
+ if (v1.isString()) {
+ return v2.isString()
+ ? jsString(callFrame, asString(v1), asString(v2))
+ : jsString(callFrame, asString(v1), v2.toPrimitiveString(callFrame));
+ }
+
+ // All other cases are pretty uncommon
+ return jsAddSlowCase(callFrame, v1, v2);
+ }
+
+ inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase, const Identifier& propertyName, size_t& slotOffset)
+ {
+ JSCell* cell = base.asCell();
+ size_t count = 0;
+
+ while (slotBase != cell) {
+ JSValue v = cell->structure()->prototypeForLookup(callFrame);
+
+ // If we didn't find slotBase in base's prototype chain, then base
+ // must be a proxy for another object.
+
+ if (v.isNull())
+ return 0;
+
+ cell = v.asCell();
+
+ // Since we're accessing a prototype in a loop, it's a good bet that it
+ // should not be treated as a dictionary.
+ if (cell->structure()->isDictionary()) {
+ asObject(cell)->flattenDictionaryObject(callFrame->globalData());
+ if (slotBase == cell)
+ slotOffset = cell->structure()->get(callFrame->globalData(), propertyName);
+ }
+
+ ++count;
+ }
+
+ ASSERT(count);
+ return count;
+ }
+
+ inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base)
+ {
+ size_t count = 0;
+ while (1) {
+ JSValue v = base->structure()->prototypeForLookup(callFrame);
+ if (v.isNull())
+ return count;
+
+ base = v.asCell();
+
+ // Since we're accessing a prototype in a loop, it's a good bet that it
+ // should not be treated as a dictionary.
+ if (base->structure()->isDictionary())
+ asObject(base)->flattenDictionaryObject(callFrame->globalData());
+
+ ++count;
+ }
+ }
+
+ ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain, bool isStrictPut)
+ {
+ ScopeChainIterator iter = scopeChain->begin();
+ ScopeChainIterator next = iter;
+ ++next;
+ ScopeChainIterator end = scopeChain->end();
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ JSObject* base;
+ while (true) {
+ base = iter->get();
+ if (next == end) {
+ if (isStrictPut && !base->getPropertySlot(callFrame, property, slot))
+ return JSValue();
+ return base;
+ }
+ if (base->getPropertySlot(callFrame, property, slot))
+ return base;
+
+ iter = next;
+ ++next;
+ }
+
+ ASSERT_NOT_REACHED();
+ return JSValue();
+ }
+} // namespace JSC
+
+#endif // Operations_h
diff --git a/Source/JavaScriptCore/runtime/Options.cpp b/Source/JavaScriptCore/runtime/Options.cpp
new file mode 100644
index 000000000..68d10b7bd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Options.cpp
@@ -0,0 +1,214 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Options.h"
+
+#include <limits>
+#include <wtf/PageBlock.h>
+
+#if OS(DARWIN) && ENABLE(PARALLEL_GC)
+#include <sys/sysctl.h>
+#endif
+
+// Set to 1 to control the heuristics using environment variables.
+#define ENABLE_RUN_TIME_HEURISTICS 0
+
+#if ENABLE(RUN_TIME_HEURISTICS)
+#include <stdio.h>
+#include <stdlib.h>
+#include <wtf/StdLibExtras.h>
+#endif
+
+namespace JSC { namespace Options {
+
+unsigned maximumOptimizationCandidateInstructionCount;
+
+unsigned maximumFunctionForCallInlineCandidateInstructionCount;
+unsigned maximumFunctionForConstructInlineCandidateInstructionCount;
+
+unsigned maximumInliningDepth;
+
+int32_t executionCounterValueForOptimizeAfterWarmUp;
+int32_t executionCounterValueForOptimizeAfterLongWarmUp;
+int32_t executionCounterValueForDontOptimizeAnytimeSoon;
+int32_t executionCounterValueForOptimizeSoon;
+int32_t executionCounterValueForOptimizeNextInvocation;
+
+int32_t executionCounterIncrementForLoop;
+int32_t executionCounterIncrementForReturn;
+
+unsigned desiredSpeculativeSuccessFailRatio;
+
+double likelyToTakeSlowCaseThreshold;
+double couldTakeSlowCaseThreshold;
+unsigned likelyToTakeSlowCaseMinimumCount;
+unsigned couldTakeSlowCaseMinimumCount;
+
+double osrExitProminenceForFrequentExitSite;
+
+unsigned largeFailCountThresholdBase;
+unsigned largeFailCountThresholdBaseForLoop;
+
+unsigned reoptimizationRetryCounterMax;
+unsigned reoptimizationRetryCounterStep;
+
+unsigned minimumOptimizationDelay;
+unsigned maximumOptimizationDelay;
+double desiredProfileLivenessRate;
+double desiredProfileFullnessRate;
+
+double doubleVoteRatioForDoubleFormat;
+
+unsigned minimumNumberOfScansBetweenRebalance;
+unsigned gcMarkStackSegmentSize;
+unsigned minimumNumberOfCellsToKeep;
+unsigned maximumNumberOfSharedSegments;
+unsigned sharedStackWakeupThreshold;
+unsigned numberOfGCMarkers;
+unsigned opaqueRootMergeThreshold;
+
+#if ENABLE(RUN_TIME_HEURISTICS)
+static bool parse(const char* string, int32_t& value)
+{
+ return sscanf(string, "%d", &value) == 1;
+}
+
+static bool parse(const char* string, unsigned& value)
+{
+ return sscanf(string, "%u", &value) == 1;
+}
+
+static bool parse(const char* string, double& value)
+{
+ return sscanf(string, "%lf", &value) == 1;
+}
+
+template<typename T, typename U>
+void setHeuristic(T& variable, const char* name, U value)
+{
+ const char* stringValue = getenv(name);
+ if (!stringValue) {
+ variable = safeCast<T>(value);
+ return;
+ }
+
+ if (parse(stringValue, variable))
+ return;
+
+ fprintf(stderr, "WARNING: failed to parse %s=%s\n", name, stringValue);
+ variable = safeCast<T>(value);
+}
+
+#define SET(variable, value) setHeuristic(variable, "JSC_" #variable, value)
+#else
+#define SET(variable, value) variable = value
+#endif
+
+void initializeOptions()
+{
+ SET(maximumOptimizationCandidateInstructionCount, 1000);
+
+ SET(maximumFunctionForCallInlineCandidateInstructionCount, 150);
+ SET(maximumFunctionForConstructInlineCandidateInstructionCount, 80);
+
+ SET(maximumInliningDepth, 5);
+
+ SET(executionCounterValueForOptimizeAfterWarmUp, -1000);
+ SET(executionCounterValueForOptimizeAfterLongWarmUp, -5000);
+ SET(executionCounterValueForDontOptimizeAnytimeSoon, std::numeric_limits<int32_t>::min());
+ SET(executionCounterValueForOptimizeSoon, -1000);
+ SET(executionCounterValueForOptimizeNextInvocation, 0);
+
+ SET(executionCounterIncrementForLoop, 1);
+ SET(executionCounterIncrementForReturn, 15);
+
+ SET(desiredSpeculativeSuccessFailRatio, 6);
+
+ SET(likelyToTakeSlowCaseThreshold, 0.15);
+ SET(couldTakeSlowCaseThreshold, 0.05); // Shouldn't be zero because some ops will spuriously take slow case, for example for linking or caching.
+ SET(likelyToTakeSlowCaseMinimumCount, 100);
+ SET(couldTakeSlowCaseMinimumCount, 10);
+
+ SET(osrExitProminenceForFrequentExitSite, 0.3);
+
+ SET(largeFailCountThresholdBase, 20);
+ SET(largeFailCountThresholdBaseForLoop, 1);
+
+ SET(reoptimizationRetryCounterStep, 1);
+
+ SET(minimumOptimizationDelay, 1);
+ SET(maximumOptimizationDelay, 5);
+ SET(desiredProfileLivenessRate, 0.75);
+ SET(desiredProfileFullnessRate, 0.35);
+
+ SET(doubleVoteRatioForDoubleFormat, 2);
+
+ SET(minimumNumberOfScansBetweenRebalance, 10000);
+ SET(gcMarkStackSegmentSize, pageSize());
+ SET(minimumNumberOfCellsToKeep, 10);
+ SET(maximumNumberOfSharedSegments, 3);
+ SET(sharedStackWakeupThreshold, 1);
+ SET(opaqueRootMergeThreshold, 1000);
+
+ int cpusToUse = 1;
+#if OS(DARWIN) && ENABLE(PARALLEL_GC)
+ int name[2];
+ size_t valueSize = sizeof(cpusToUse);
+ name[0] = CTL_HW;
+ name[1] = HW_AVAILCPU;
+ sysctl(name, 2, &cpusToUse, &valueSize, 0, 0);
+#endif
+ // We don't scale so well beyond 4.
+ if (cpusToUse > 4)
+ cpusToUse = 4;
+ // Be paranoid, it is the OS we're dealing with, after all.
+ if (cpusToUse < 1)
+ cpusToUse = 1;
+
+ SET(numberOfGCMarkers, cpusToUse);
+
+ ASSERT(executionCounterValueForDontOptimizeAnytimeSoon <= executionCounterValueForOptimizeAfterLongWarmUp);
+ ASSERT(executionCounterValueForOptimizeAfterLongWarmUp <= executionCounterValueForOptimizeAfterWarmUp);
+ ASSERT(executionCounterValueForOptimizeAfterWarmUp <= executionCounterValueForOptimizeSoon);
+ ASSERT(executionCounterValueForOptimizeAfterWarmUp < 0);
+ ASSERT(executionCounterValueForOptimizeSoon <= executionCounterValueForOptimizeNextInvocation);
+
+ // Compute the maximum value of the reoptimization retry counter. This is simply
+ // the largest value at which we don't overflow the execute counter, when using it
+ // to left-shift the execution counter by this amount. Currently the value ends
+ // up being 18, so this loop is not so terrible; it probably takes up ~100 cycles
+ // total on a 32-bit processor.
+ reoptimizationRetryCounterMax = 0;
+ while ((static_cast<int64_t>(executionCounterValueForOptimizeAfterLongWarmUp) << (reoptimizationRetryCounterMax + 1)) >= static_cast<int64_t>(std::numeric_limits<int32_t>::min()))
+ reoptimizationRetryCounterMax++;
+
+ ASSERT((static_cast<int64_t>(executionCounterValueForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) < 0);
+ ASSERT((static_cast<int64_t>(executionCounterValueForOptimizeAfterLongWarmUp) << reoptimizationRetryCounterMax) >= static_cast<int64_t>(std::numeric_limits<int32_t>::min()));
+}
+
+} } // namespace JSC::Options
+
+
diff --git a/Source/JavaScriptCore/runtime/Options.h b/Source/JavaScriptCore/runtime/Options.h
new file mode 100644
index 000000000..f7cc5f4e8
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Options.h
@@ -0,0 +1,84 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Options_h
+#define Options_h
+
+#include <stdint.h>
+
+namespace JSC { namespace Options {
+
+extern unsigned maximumOptimizationCandidateInstructionCount;
+
+extern unsigned maximumFunctionForCallInlineCandidateInstructionCount;
+extern unsigned maximumFunctionForConstructInlineCandidateInstructionCount;
+
+extern unsigned maximumInliningDepth; // Depth of inline stack, so 1 = no inlining, 2 = one level, etc.
+
+extern int32_t executionCounterValueForOptimizeAfterWarmUp;
+extern int32_t executionCounterValueForOptimizeAfterLongWarmUp;
+extern int32_t executionCounterValueForDontOptimizeAnytimeSoon;
+extern int32_t executionCounterValueForOptimizeSoon;
+extern int32_t executionCounterValueForOptimizeNextInvocation;
+
+extern int32_t executionCounterIncrementForLoop;
+extern int32_t executionCounterIncrementForReturn;
+
+extern unsigned desiredSpeculativeSuccessFailRatio;
+
+extern double likelyToTakeSlowCaseThreshold;
+extern double couldTakeSlowCaseThreshold;
+extern unsigned likelyToTakeSlowCaseMinimumCount;
+extern unsigned couldTakeSlowCaseMinimumCount;
+
+extern double osrExitProminenceForFrequentExitSite;
+
+extern unsigned largeFailCountThresholdBase;
+extern unsigned largeFailCountThresholdBaseForLoop;
+
+extern unsigned reoptimizationRetryCounterMax;
+extern unsigned reoptimizationRetryCounterStep;
+
+extern unsigned minimumOptimizationDelay;
+extern unsigned maximumOptimizationDelay;
+extern double desiredProfileLivenessRate;
+extern double desiredProfileFullnessRate;
+
+extern double doubleVoteRatioForDoubleFormat;
+
+extern unsigned minimumNumberOfScansBetweenRebalance;
+extern unsigned gcMarkStackSegmentSize;
+extern unsigned minimumNumberOfCellsToKeep;
+extern unsigned maximumNumberOfSharedSegments;
+extern unsigned sharedStackWakeupThreshold;
+extern unsigned numberOfGCMarkers;
+extern unsigned opaqueRootMergeThreshold;
+
+void initializeOptions();
+
+} } // namespace JSC::Options
+
+#endif // Options_h
+
diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp
new file mode 100644
index 000000000..9d62dfc98
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.cpp
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+
+#include "config.h"
+
+#include "PropertyDescriptor.h"
+
+#include "GetterSetter.h"
+#include "JSObject.h"
+#include "Operations.h"
+
+namespace JSC {
+unsigned PropertyDescriptor::defaultAttributes = (DontDelete << 1) - 1;
+
+bool PropertyDescriptor::writable() const
+{
+ ASSERT(!isAccessorDescriptor());
+ return !(m_attributes & ReadOnly);
+}
+
+bool PropertyDescriptor::enumerable() const
+{
+ return !(m_attributes & DontEnum);
+}
+
+bool PropertyDescriptor::configurable() const
+{
+ return !(m_attributes & DontDelete);
+}
+
+bool PropertyDescriptor::isDataDescriptor() const
+{
+ return m_value || (m_seenAttributes & WritablePresent);
+}
+
+bool PropertyDescriptor::isGenericDescriptor() const
+{
+ return !isAccessorDescriptor() && !isDataDescriptor();
+}
+
+bool PropertyDescriptor::isAccessorDescriptor() const
+{
+ return m_getter || m_setter;
+}
+
+void PropertyDescriptor::setUndefined()
+{
+ m_value = jsUndefined();
+ m_attributes = ReadOnly | DontDelete | DontEnum;
+}
+
+JSValue PropertyDescriptor::getter() const
+{
+ ASSERT(isAccessorDescriptor());
+ return m_getter;
+}
+
+JSValue PropertyDescriptor::setter() const
+{
+ ASSERT(isAccessorDescriptor());
+ return m_setter;
+}
+
+void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes)
+{
+ ASSERT(value);
+ m_attributes = attributes;
+ if (value.isGetterSetter()) {
+ GetterSetter* accessor = asGetterSetter(value);
+
+ m_getter = accessor->getter();
+ if (m_getter)
+ m_attributes |= Getter;
+
+ m_setter = accessor->setter();
+ if (m_setter)
+ m_attributes |= Setter;
+
+ ASSERT(m_getter || m_setter);
+ m_seenAttributes = EnumerablePresent | ConfigurablePresent;
+ m_attributes &= ~ReadOnly;
+ } else {
+ m_value = value;
+ m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent;
+ }
+}
+
+void PropertyDescriptor::setAccessorDescriptor(GetterSetter* accessor, unsigned attributes)
+{
+ ASSERT(attributes & (Getter | Setter));
+ ASSERT(accessor->getter() || accessor->setter());
+ ASSERT(!accessor->getter() == !(attributes & Getter));
+ ASSERT(!accessor->setter() == !(attributes & Setter));
+ m_attributes = attributes;
+ m_getter = accessor->getter();
+ m_setter = accessor->setter();
+ m_attributes &= ~ReadOnly;
+ m_seenAttributes = EnumerablePresent | ConfigurablePresent;
+}
+
+void PropertyDescriptor::setWritable(bool writable)
+{
+ if (writable)
+ m_attributes &= ~ReadOnly;
+ else
+ m_attributes |= ReadOnly;
+ m_seenAttributes |= WritablePresent;
+}
+
+void PropertyDescriptor::setEnumerable(bool enumerable)
+{
+ if (enumerable)
+ m_attributes &= ~DontEnum;
+ else
+ m_attributes |= DontEnum;
+ m_seenAttributes |= EnumerablePresent;
+}
+
+void PropertyDescriptor::setConfigurable(bool configurable)
+{
+ if (configurable)
+ m_attributes &= ~DontDelete;
+ else
+ m_attributes |= DontDelete;
+ m_seenAttributes |= ConfigurablePresent;
+}
+
+void PropertyDescriptor::setSetter(JSValue setter)
+{
+ m_setter = setter;
+ m_attributes |= Setter;
+ m_attributes &= ~ReadOnly;
+}
+
+void PropertyDescriptor::setGetter(JSValue getter)
+{
+ m_getter = getter;
+ m_attributes |= Getter;
+ m_attributes &= ~ReadOnly;
+}
+
+bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const
+{
+ if (!other.m_value == m_value ||
+ !other.m_getter == m_getter ||
+ !other.m_setter == m_setter)
+ return false;
+ return (!m_value || JSValue::strictEqual(exec, other.m_value, m_value)) &&
+ (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter)) &&
+ (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter)) &&
+ attributesEqual(other);
+}
+
+bool PropertyDescriptor::attributesEqual(const PropertyDescriptor& other) const
+{
+ unsigned mismatch = other.m_attributes ^ m_attributes;
+ unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes;
+ if (sharedSeen & WritablePresent && mismatch & ReadOnly)
+ return false;
+ if (sharedSeen & ConfigurablePresent && mismatch & DontDelete)
+ return false;
+ if (sharedSeen & EnumerablePresent && mismatch & DontEnum)
+ return false;
+ return true;
+}
+
+unsigned PropertyDescriptor::attributesWithOverride(const PropertyDescriptor& other) const
+{
+ unsigned mismatch = other.m_attributes ^ m_attributes;
+ unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes;
+ unsigned newAttributes = m_attributes & defaultAttributes;
+ if (sharedSeen & WritablePresent && mismatch & ReadOnly)
+ newAttributes ^= ReadOnly;
+ if (sharedSeen & ConfigurablePresent && mismatch & DontDelete)
+ newAttributes ^= DontDelete;
+ if (sharedSeen & EnumerablePresent && mismatch & DontEnum)
+ newAttributes ^= DontEnum;
+ return newAttributes;
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/PropertyDescriptor.h b/Source/JavaScriptCore/runtime/PropertyDescriptor.h
new file mode 100644
index 000000000..bebf5e826
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/PropertyDescriptor.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef PropertyDescriptor_h
+#define PropertyDescriptor_h
+
+#include "JSValue.h"
+
+namespace JSC {
+ class GetterSetter;
+
+ class PropertyDescriptor {
+ public:
+ PropertyDescriptor()
+ : m_attributes(defaultAttributes)
+ , m_seenAttributes(0)
+ {
+ }
+ bool writable() const;
+ bool enumerable() const;
+ bool configurable() const;
+ bool isDataDescriptor() const;
+ bool isGenericDescriptor() const;
+ bool isAccessorDescriptor() const;
+ unsigned attributes() const { return m_attributes; }
+ JSValue value() const { return m_value; }
+ JSValue getter() const;
+ JSValue setter() const;
+ void setUndefined();
+ void setDescriptor(JSValue value, unsigned attributes);
+ void setAccessorDescriptor(GetterSetter* accessor, unsigned attributes);
+ void setWritable(bool);
+ void setEnumerable(bool);
+ void setConfigurable(bool);
+ void setValue(JSValue value) { m_value = value; }
+ void setSetter(JSValue);
+ void setGetter(JSValue);
+ bool isEmpty() const { return !(m_value || m_getter || m_setter || m_seenAttributes); }
+ bool writablePresent() const { return m_seenAttributes & WritablePresent; }
+ bool enumerablePresent() const { return m_seenAttributes & EnumerablePresent; }
+ bool configurablePresent() const { return m_seenAttributes & ConfigurablePresent; }
+ bool setterPresent() const { return m_setter; }
+ bool getterPresent() const { return m_getter; }
+ bool equalTo(ExecState* exec, const PropertyDescriptor& other) const;
+ bool attributesEqual(const PropertyDescriptor& other) const;
+ unsigned attributesWithOverride(const PropertyDescriptor& other) const;
+ private:
+ static unsigned defaultAttributes;
+ bool operator==(const PropertyDescriptor&){ return false; }
+ enum { WritablePresent = 1, EnumerablePresent = 2, ConfigurablePresent = 4};
+ // May be a getter/setter
+ JSValue m_value;
+ JSValue m_getter;
+ JSValue m_setter;
+ unsigned m_attributes;
+ unsigned m_seenAttributes;
+ };
+}
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/PropertyMapHashTable.h b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
new file mode 100644
index 000000000..7c8cabb7b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/PropertyMapHashTable.h
@@ -0,0 +1,591 @@
+/*
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PropertyMapHashTable_h
+#define PropertyMapHashTable_h
+
+#include "UString.h"
+#include "WriteBarrier.h"
+#include <wtf/HashTable.h>
+#include <wtf/PassOwnPtr.h>
+#include <wtf/Vector.h>
+
+
+#ifndef NDEBUG
+#define DUMP_PROPERTYMAP_STATS 0
+#else
+#define DUMP_PROPERTYMAP_STATS 0
+#endif
+
+#if DUMP_PROPERTYMAP_STATS
+
+extern int numProbes;
+extern int numCollisions;
+extern int numRehashes;
+extern int numRemoves;
+
+#endif
+
+#define PROPERTY_MAP_DELETED_ENTRY_KEY ((StringImpl*)1)
+
+namespace JSC {
+
+inline bool isPowerOf2(unsigned v)
+{
+ // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html
+
+ return !(v & (v - 1)) && v;
+}
+
+inline unsigned nextPowerOf2(unsigned v)
+{
+ // Taken from http://www.cs.utk.edu/~vose/c-stuff/bithacks.html
+ // Devised by Sean Anderson, Sepember 14, 2001
+
+ v--;
+ v |= v >> 1;
+ v |= v >> 2;
+ v |= v >> 4;
+ v |= v >> 8;
+ v |= v >> 16;
+ v++;
+
+ return v;
+}
+
+struct PropertyMapEntry {
+ StringImpl* key;
+ unsigned offset;
+ unsigned attributes;
+ WriteBarrier<JSCell> specificValue;
+
+ PropertyMapEntry(JSGlobalData& globalData, JSCell* owner, StringImpl* key, unsigned offset, unsigned attributes, JSCell* specificValue)
+ : key(key)
+ , offset(offset)
+ , attributes(attributes)
+ , specificValue(globalData, owner, specificValue, WriteBarrier<JSCell>::MayBeNull)
+ {
+ }
+};
+
+class PropertyTable {
+ WTF_MAKE_FAST_ALLOCATED;
+
+ // This is the implementation for 'iterator' and 'const_iterator',
+ // used for iterating over the table in insertion order.
+ template<typename T>
+ class ordered_iterator {
+ public:
+ ordered_iterator<T>& operator++()
+ {
+ m_valuePtr = skipDeletedEntries(m_valuePtr + 1);
+ return *this;
+ }
+
+ bool operator==(const ordered_iterator<T>& other)
+ {
+ return m_valuePtr == other.m_valuePtr;
+ }
+
+ bool operator!=(const ordered_iterator<T>& other)
+ {
+ return m_valuePtr != other.m_valuePtr;
+ }
+
+ T& operator*()
+ {
+ return *m_valuePtr;
+ }
+
+ T* operator->()
+ {
+ return m_valuePtr;
+ }
+
+ ordered_iterator(T* valuePtr)
+ : m_valuePtr(valuePtr)
+ {
+ }
+
+ private:
+ T* m_valuePtr;
+ };
+
+public:
+ typedef StringImpl* KeyType;
+ typedef PropertyMapEntry ValueType;
+
+ // The in order iterator provides overloaded * and -> to access the Value at the current position.
+ typedef ordered_iterator<ValueType> iterator;
+ typedef ordered_iterator<const ValueType> const_iterator;
+
+ // The find_iterator is a pair of a pointer to a Value* an the entry in the index.
+ // If 'find' does not find an entry then iter.first will be 0, and iter.second will
+ // give the point in m_index where an entry should be inserted.
+ typedef std::pair<ValueType*, unsigned> find_iterator;
+
+ // Constructor is passed an initial capacity, a PropertyTable to copy, or both.
+ explicit PropertyTable(unsigned initialCapacity);
+ PropertyTable(JSGlobalData&, JSCell*, const PropertyTable&);
+ PropertyTable(JSGlobalData&, JSCell*, unsigned initialCapacity, const PropertyTable&);
+ ~PropertyTable();
+
+ // Ordered iteration methods.
+ iterator begin();
+ iterator end();
+ const_iterator begin() const;
+ const_iterator end() const;
+
+ // Find a value in the table.
+ find_iterator find(const KeyType&);
+ find_iterator findWithString(const KeyType&);
+ // Add a value to the table
+ std::pair<find_iterator, bool> add(const ValueType& entry);
+ // Remove a value from the table.
+ void remove(const find_iterator& iter);
+ void remove(const KeyType& key);
+
+ // Returns the number of values in the hashtable.
+ unsigned size() const;
+
+ // Checks if there are any values in the hashtable.
+ bool isEmpty() const;
+
+ // Number of slots in the property storage array in use, included deletedOffsets.
+ unsigned propertyStorageSize() const;
+
+ // Used to maintain a list of unused entries in the property storage.
+ void clearDeletedOffsets();
+ bool hasDeletedOffset();
+ unsigned getDeletedOffset();
+ void addDeletedOffset(unsigned offset);
+
+ // Copy this PropertyTable, ensuring the copy has at least the capacity provided.
+ PassOwnPtr<PropertyTable> copy(JSGlobalData&, JSCell* owner, unsigned newCapacity);
+
+#ifndef NDEBUG
+ size_t sizeInMemory();
+ void checkConsistency();
+#endif
+
+private:
+ PropertyTable(const PropertyTable&);
+ // Used to insert a value known not to be in the table, and where we know capacity to be available.
+ void reinsert(const ValueType& entry);
+
+ // Rehash the table. Used to grow, or to recover deleted slots.
+ void rehash(unsigned newCapacity);
+
+ // The capacity of the table of values is half of the size of the index.
+ unsigned tableCapacity() const;
+
+ // We keep an extra deleted slot after the array to make iteration work,
+ // and to use for deleted values. Index values into the array are 1-based,
+ // so this is tableCapacity() + 1.
+ // For example, if m_tableSize is 16, then tableCapacity() is 8 - but the
+ // values array is actually 9 long (the 9th used for the deleted value/
+ // iteration guard). The 8 valid entries are numbered 1..8, so the
+ // deleted index is 9 (0 being reserved for empty).
+ unsigned deletedEntryIndex() const;
+
+ // Used in iterator creation/progression.
+ template<typename T>
+ static T* skipDeletedEntries(T* valuePtr);
+
+ // The table of values lies after the hash index.
+ ValueType* table();
+ const ValueType* table() const;
+
+ // total number of used entries in the values array - by either valid entries, or deleted ones.
+ unsigned usedCount() const;
+
+ // The size in bytes of data needed for by the table.
+ size_t dataSize();
+
+ // Calculates the appropriate table size (rounds up to a power of two).
+ static unsigned sizeForCapacity(unsigned capacity);
+
+ // Check if capacity is available.
+ bool canInsert();
+
+ unsigned m_indexSize;
+ unsigned m_indexMask;
+ unsigned* m_index;
+ unsigned m_keyCount;
+ unsigned m_deletedCount;
+ OwnPtr< Vector<unsigned> > m_deletedOffsets;
+
+ static const unsigned MinimumTableSize = 16;
+ static const unsigned EmptyEntryIndex = 0;
+};
+
+inline PropertyTable::PropertyTable(unsigned initialCapacity)
+ : m_indexSize(sizeForCapacity(initialCapacity))
+ , m_indexMask(m_indexSize - 1)
+ , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
+ , m_keyCount(0)
+ , m_deletedCount(0)
+{
+ ASSERT(isPowerOf2(m_indexSize));
+}
+
+inline PropertyTable::PropertyTable(JSGlobalData&, JSCell* owner, const PropertyTable& other)
+ : m_indexSize(other.m_indexSize)
+ , m_indexMask(other.m_indexMask)
+ , m_index(static_cast<unsigned*>(fastMalloc(dataSize())))
+ , m_keyCount(other.m_keyCount)
+ , m_deletedCount(other.m_deletedCount)
+{
+ ASSERT(isPowerOf2(m_indexSize));
+
+ memcpy(m_index, other.m_index, dataSize());
+
+ iterator end = this->end();
+ for (iterator iter = begin(); iter != end; ++iter) {
+ iter->key->ref();
+ Heap::writeBarrier(owner, iter->specificValue.get());
+ }
+
+ // Copy the m_deletedOffsets vector.
+ Vector<unsigned>* otherDeletedOffsets = other.m_deletedOffsets.get();
+ if (otherDeletedOffsets)
+ m_deletedOffsets = adoptPtr(new Vector<unsigned>(*otherDeletedOffsets));
+}
+
+inline PropertyTable::PropertyTable(JSGlobalData&, JSCell* owner, unsigned initialCapacity, const PropertyTable& other)
+ : m_indexSize(sizeForCapacity(initialCapacity))
+ , m_indexMask(m_indexSize - 1)
+ , m_index(static_cast<unsigned*>(fastZeroedMalloc(dataSize())))
+ , m_keyCount(0)
+ , m_deletedCount(0)
+{
+ ASSERT(isPowerOf2(m_indexSize));
+ ASSERT(initialCapacity >= other.m_keyCount);
+
+ const_iterator end = other.end();
+ for (const_iterator iter = other.begin(); iter != end; ++iter) {
+ ASSERT(canInsert());
+ reinsert(*iter);
+ iter->key->ref();
+ Heap::writeBarrier(owner, iter->specificValue.get());
+ }
+
+ // Copy the m_deletedOffsets vector.
+ Vector<unsigned>* otherDeletedOffsets = other.m_deletedOffsets.get();
+ if (otherDeletedOffsets)
+ m_deletedOffsets = adoptPtr(new Vector<unsigned>(*otherDeletedOffsets));
+}
+
+inline PropertyTable::~PropertyTable()
+{
+ iterator end = this->end();
+ for (iterator iter = begin(); iter != end; ++iter)
+ iter->key->deref();
+
+ fastFree(m_index);
+}
+
+inline PropertyTable::iterator PropertyTable::begin()
+{
+ return iterator(skipDeletedEntries(table()));
+}
+
+inline PropertyTable::iterator PropertyTable::end()
+{
+ return iterator(table() + usedCount());
+}
+
+inline PropertyTable::const_iterator PropertyTable::begin() const
+{
+ return const_iterator(skipDeletedEntries(table()));
+}
+
+inline PropertyTable::const_iterator PropertyTable::end() const
+{
+ return const_iterator(table() + usedCount());
+}
+
+inline PropertyTable::find_iterator PropertyTable::find(const KeyType& key)
+{
+ ASSERT(key);
+ ASSERT(key->isIdentifier());
+ unsigned hash = key->existingHash();
+ unsigned step = 0;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+#endif
+
+ while (true) {
+ unsigned entryIndex = m_index[hash & m_indexMask];
+ if (entryIndex == EmptyEntryIndex)
+ return std::make_pair((ValueType*)0, hash & m_indexMask);
+ if (key == table()[entryIndex - 1].key)
+ return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+
+ if (!step)
+ step = WTF::doubleHash(key->existingHash()) | 1;
+ hash += step;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+ }
+}
+
+inline PropertyTable::find_iterator PropertyTable::findWithString(const KeyType& key)
+{
+ ASSERT(key);
+ ASSERT(!key->isIdentifier() && !key->hasHash());
+ unsigned hash = key->hash();
+ unsigned step = 0;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+#endif
+
+ while (true) {
+ unsigned entryIndex = m_index[hash & m_indexMask];
+ if (entryIndex == EmptyEntryIndex)
+ return std::make_pair((ValueType*)0, hash & m_indexMask);
+ if (equal(key, table()[entryIndex - 1].key))
+ return std::make_pair(&table()[entryIndex - 1], hash & m_indexMask);
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+
+ if (!step)
+ step = WTF::doubleHash(key->existingHash()) | 1;
+ hash += step;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+ }
+}
+
+inline std::pair<PropertyTable::find_iterator, bool> PropertyTable::add(const ValueType& entry)
+{
+ // Look for a value with a matching key already in the array.
+ find_iterator iter = find(entry.key);
+ if (iter.first)
+ return std::make_pair(iter, false);
+
+ // Ref the key
+ entry.key->ref();
+
+ // ensure capacity is available.
+ if (!canInsert()) {
+ rehash(m_keyCount + 1);
+ iter = find(entry.key);
+ ASSERT(!iter.first);
+ }
+
+ // Allocate a slot in the hashtable, and set the index to reference this.
+ unsigned entryIndex = usedCount() + 1;
+ m_index[iter.second] = entryIndex;
+ iter.first = &table()[entryIndex - 1];
+ *iter.first = entry;
+
+ ++m_keyCount;
+ return std::make_pair(iter, true);
+}
+
+inline void PropertyTable::remove(const find_iterator& iter)
+{
+ // Removing a key that doesn't exist does nothing!
+ if (!iter.first)
+ return;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRemoves;
+#endif
+
+ // Replace this one element with the deleted sentinel. Also clear out
+ // the entry so we can iterate all the entries as needed.
+ m_index[iter.second] = deletedEntryIndex();
+ iter.first->key->deref();
+ iter.first->key = PROPERTY_MAP_DELETED_ENTRY_KEY;
+
+ ASSERT(m_keyCount >= 1);
+ --m_keyCount;
+ ++m_deletedCount;
+
+ if (m_deletedCount * 4 >= m_indexSize)
+ rehash(m_keyCount);
+}
+
+inline void PropertyTable::remove(const KeyType& key)
+{
+ remove(find(key));
+}
+
+// returns the number of values in the hashtable.
+inline unsigned PropertyTable::size() const
+{
+ return m_keyCount;
+}
+
+inline bool PropertyTable::isEmpty() const
+{
+ return !m_keyCount;
+}
+
+inline unsigned PropertyTable::propertyStorageSize() const
+{
+ return size() + (m_deletedOffsets ? m_deletedOffsets->size() : 0);
+}
+
+inline void PropertyTable::clearDeletedOffsets()
+{
+ m_deletedOffsets.clear();
+}
+
+inline bool PropertyTable::hasDeletedOffset()
+{
+ return m_deletedOffsets && !m_deletedOffsets->isEmpty();
+}
+
+inline unsigned PropertyTable::getDeletedOffset()
+{
+ unsigned offset = m_deletedOffsets->last();
+ m_deletedOffsets->removeLast();
+ return offset;
+}
+
+inline void PropertyTable::addDeletedOffset(unsigned offset)
+{
+ if (!m_deletedOffsets)
+ m_deletedOffsets = adoptPtr(new Vector<unsigned>);
+ m_deletedOffsets->append(offset);
+}
+
+inline PassOwnPtr<PropertyTable> PropertyTable::copy(JSGlobalData& globalData, JSCell* owner, unsigned newCapacity)
+{
+ ASSERT(newCapacity >= m_keyCount);
+
+ // Fast case; if the new table will be the same m_indexSize as this one, we can memcpy it,
+ // save rehashing all keys.
+ if (sizeForCapacity(newCapacity) == m_indexSize)
+ return adoptPtr(new PropertyTable(globalData, owner, *this));
+ return adoptPtr(new PropertyTable(globalData, owner, newCapacity, *this));
+}
+
+#ifndef NDEBUG
+inline size_t PropertyTable::sizeInMemory()
+{
+ size_t result = sizeof(PropertyTable) + dataSize();
+ if (m_deletedOffsets)
+ result += (m_deletedOffsets->capacity() * sizeof(unsigned));
+ return result;
+}
+#endif
+
+inline void PropertyTable::reinsert(const ValueType& entry)
+{
+ // Used to insert a value known not to be in the table, and where
+ // we know capacity to be available.
+ ASSERT(canInsert());
+ find_iterator iter = find(entry.key);
+ ASSERT(!iter.first);
+
+ unsigned entryIndex = usedCount() + 1;
+ m_index[iter.second] = entryIndex;
+ table()[entryIndex - 1] = entry;
+
+ ++m_keyCount;
+}
+
+inline void PropertyTable::rehash(unsigned newCapacity)
+{
+ unsigned* oldEntryIndices = m_index;
+ iterator iter = this->begin();
+ iterator end = this->end();
+
+ m_indexSize = sizeForCapacity(newCapacity);
+ m_indexMask = m_indexSize - 1;
+ m_keyCount = 0;
+ m_deletedCount = 0;
+ m_index = static_cast<unsigned*>(fastZeroedMalloc(dataSize()));
+
+ for (; iter != end; ++iter) {
+ ASSERT(canInsert());
+ reinsert(*iter);
+ }
+
+ fastFree(oldEntryIndices);
+}
+
+inline unsigned PropertyTable::tableCapacity() const { return m_indexSize >> 1; }
+
+inline unsigned PropertyTable::deletedEntryIndex() const { return tableCapacity() + 1; }
+
+template<typename T>
+inline T* PropertyTable::skipDeletedEntries(T* valuePtr)
+{
+ while (valuePtr->key == PROPERTY_MAP_DELETED_ENTRY_KEY)
+ ++valuePtr;
+ return valuePtr;
+}
+
+inline PropertyTable::ValueType* PropertyTable::table()
+{
+ // The table of values lies after the hash index.
+ return reinterpret_cast<ValueType*>(m_index + m_indexSize);
+}
+
+inline const PropertyTable::ValueType* PropertyTable::table() const
+{
+ // The table of values lies after the hash index.
+ return reinterpret_cast<const ValueType*>(m_index + m_indexSize);
+}
+
+inline unsigned PropertyTable::usedCount() const
+{
+ // Total number of used entries in the values array - by either valid entries, or deleted ones.
+ return m_keyCount + m_deletedCount;
+}
+
+inline size_t PropertyTable::dataSize()
+{
+ // The size in bytes of data needed for by the table.
+ return m_indexSize * sizeof(unsigned) + ((tableCapacity()) + 1) * sizeof(ValueType);
+}
+
+inline unsigned PropertyTable::sizeForCapacity(unsigned capacity)
+{
+ if (capacity < 8)
+ return MinimumTableSize;
+ return nextPowerOf2(capacity + 1) * 2;
+}
+
+inline bool PropertyTable::canInsert()
+{
+ return usedCount() < tableCapacity();
+}
+
+} // namespace JSC
+
+#endif // PropertyMapHashTable_h
diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.cpp b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
new file mode 100644
index 000000000..8efb4065e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/PropertyNameArray.cpp
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "PropertyNameArray.h"
+
+#include "JSObject.h"
+#include "ScopeChain.h"
+#include "Structure.h"
+#include "StructureChain.h"
+
+namespace JSC {
+
+static const size_t setThreshold = 20;
+
+void PropertyNameArray::add(StringImpl* identifier)
+{
+ ASSERT(!identifier || identifier == StringImpl::empty() || identifier->isIdentifier());
+
+ size_t size = m_data->propertyNameVector().size();
+ if (size < setThreshold) {
+ for (size_t i = 0; i < size; ++i) {
+ if (identifier == m_data->propertyNameVector()[i].impl())
+ return;
+ }
+ } else {
+ if (m_set.isEmpty()) {
+ for (size_t i = 0; i < size; ++i)
+ m_set.add(m_data->propertyNameVector()[i].impl());
+ }
+ if (!m_set.add(identifier).second)
+ return;
+ }
+
+ addKnownUnique(identifier);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/PropertyNameArray.h b/Source/JavaScriptCore/runtime/PropertyNameArray.h
new file mode 100644
index 000000000..0da930f17
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/PropertyNameArray.h
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PropertyNameArray_h
+#define PropertyNameArray_h
+
+#include "CallFrame.h"
+#include "Identifier.h"
+#include <wtf/HashSet.h>
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/Vector.h>
+
+namespace JSC {
+
+ class Structure;
+ class StructureChain;
+
+ // FIXME: Rename to PropertyNameArray.
+ class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> {
+ public:
+ typedef Vector<Identifier, 20> PropertyNameVector;
+
+ static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); }
+
+ PropertyNameVector& propertyNameVector() { return m_propertyNameVector; }
+
+ private:
+ PropertyNameArrayData()
+ {
+ }
+
+ PropertyNameVector m_propertyNameVector;
+ };
+
+ // FIXME: Rename to PropertyNameArrayBuilder.
+ class PropertyNameArray {
+ public:
+ PropertyNameArray(JSGlobalData* globalData)
+ : m_data(PropertyNameArrayData::create())
+ , m_globalData(globalData)
+ , m_shouldCache(true)
+ {
+ }
+
+ PropertyNameArray(ExecState* exec)
+ : m_data(PropertyNameArrayData::create())
+ , m_globalData(&exec->globalData())
+ , m_shouldCache(true)
+ {
+ }
+
+ JSGlobalData* globalData() { return m_globalData; }
+
+ void add(const Identifier& identifier) { add(identifier.impl()); }
+ void add(StringImpl*);
+ void addKnownUnique(StringImpl* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); }
+
+ Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; }
+ const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; }
+
+ void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; }
+ PropertyNameArrayData* data() { return m_data.get(); }
+ PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); }
+
+ // FIXME: Remove these functions.
+ typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator;
+ size_t size() const { return m_data->propertyNameVector().size(); }
+ const_iterator begin() const { return m_data->propertyNameVector().begin(); }
+ const_iterator end() const { return m_data->propertyNameVector().end(); }
+
+ private:
+ typedef HashSet<StringImpl*, PtrHash<StringImpl*> > IdentifierSet;
+
+ RefPtr<PropertyNameArrayData> m_data;
+ IdentifierSet m_set;
+ JSGlobalData* m_globalData;
+ bool m_shouldCache;
+ };
+
+} // namespace JSC
+
+#endif // PropertyNameArray_h
diff --git a/Source/JavaScriptCore/runtime/PropertySlot.cpp b/Source/JavaScriptCore/runtime/PropertySlot.cpp
new file mode 100644
index 000000000..edabd7a6e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/PropertySlot.cpp
@@ -0,0 +1,44 @@
+/*
+ * 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"
+
+namespace JSC {
+
+JSValue PropertySlot::functionGetter(ExecState* exec) const
+{
+ // Prevent getter functions from observing execution if an exception is pending.
+ if (exec->hadException())
+ return exec->exception();
+
+ CallData callData;
+ CallType callType = m_data.getterFunc->methodTable()->getCallData(m_data.getterFunc, callData);
+
+ // Only objects can have accessor properties.
+ // If the base is WebCore's global object then we need to substitute the shell.
+ ASSERT(m_slotBase.isObject());
+ return call(exec, m_data.getterFunc, callType, callData, m_thisValue.toThisObject(exec), exec->emptyList());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/PropertySlot.h b/Source/JavaScriptCore/runtime/PropertySlot.h
new file mode 100644
index 000000000..8557e6d24
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/PropertySlot.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (C) 2005, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef PropertySlot_h
+#define PropertySlot_h
+
+#include "Identifier.h"
+#include "JSValue.h"
+#include "Register.h"
+#include <wtf/Assertions.h>
+#include <wtf/NotFound.h>
+
+namespace JSC {
+
+ class ExecState;
+ class JSObject;
+
+#define JSC_VALUE_MARKER 0
+#define INDEX_GETTER_MARKER reinterpret_cast<GetValueFunc>(2)
+#define GETTER_FUNCTION_MARKER reinterpret_cast<GetValueFunc>(3)
+
+ class PropertySlot {
+ public:
+ enum CachedPropertyType {
+ Uncacheable,
+ Getter,
+ Custom,
+ Value
+ };
+
+ PropertySlot()
+ : m_cachedPropertyType(Uncacheable)
+ {
+ clearBase();
+ clearOffset();
+ clearValue();
+ }
+
+ explicit PropertySlot(const JSValue base)
+ : m_slotBase(base)
+ , m_cachedPropertyType(Uncacheable)
+ {
+ clearOffset();
+ clearValue();
+ }
+
+ typedef JSValue (*GetValueFunc)(ExecState*, JSValue slotBase, const Identifier&);
+ typedef JSValue (*GetIndexValueFunc)(ExecState*, JSValue slotBase, unsigned);
+
+ JSValue getValue(ExecState* exec, const Identifier& propertyName) const
+ {
+ if (m_getValue == JSC_VALUE_MARKER)
+ return m_value;
+ if (m_getValue == INDEX_GETTER_MARKER)
+ return m_getIndexValue(exec, slotBase(), index());
+ if (m_getValue == GETTER_FUNCTION_MARKER)
+ return functionGetter(exec);
+ return m_getValue(exec, slotBase(), propertyName);
+ }
+
+ JSValue getValue(ExecState* exec, unsigned propertyName) const
+ {
+ if (m_getValue == JSC_VALUE_MARKER)
+ return m_value;
+ if (m_getValue == INDEX_GETTER_MARKER)
+ return m_getIndexValue(exec, m_slotBase, m_data.index);
+ if (m_getValue == GETTER_FUNCTION_MARKER)
+ return functionGetter(exec);
+ return m_getValue(exec, slotBase(), Identifier::from(exec, propertyName));
+ }
+
+ CachedPropertyType cachedPropertyType() const { return m_cachedPropertyType; }
+ bool isCacheable() const { return m_cachedPropertyType != Uncacheable; }
+ bool isCacheableValue() const { return m_cachedPropertyType == Value; }
+ size_t cachedOffset() const
+ {
+ ASSERT(isCacheable());
+ return m_offset;
+ }
+
+ void setValue(JSValue slotBase, JSValue value)
+ {
+ ASSERT(value);
+ clearOffset();
+ m_getValue = JSC_VALUE_MARKER;
+ m_slotBase = slotBase;
+ m_value = value;
+ }
+
+ void setValue(JSValue slotBase, JSValue value, size_t offset)
+ {
+ ASSERT(value);
+ m_getValue = JSC_VALUE_MARKER;
+ m_slotBase = slotBase;
+ m_value = value;
+ m_offset = offset;
+ m_cachedPropertyType = Value;
+ }
+
+ void setValue(JSValue value)
+ {
+ ASSERT(value);
+ clearBase();
+ clearOffset();
+ m_getValue = JSC_VALUE_MARKER;
+ m_value = value;
+ }
+
+ void setCustom(JSValue slotBase, GetValueFunc getValue)
+ {
+ ASSERT(slotBase);
+ ASSERT(getValue);
+ m_getValue = getValue;
+ m_getIndexValue = 0;
+ m_slotBase = slotBase;
+ }
+
+ void setCacheableCustom(JSValue slotBase, GetValueFunc getValue)
+ {
+ ASSERT(slotBase);
+ ASSERT(getValue);
+ m_getValue = getValue;
+ m_getIndexValue = 0;
+ m_slotBase = slotBase;
+ m_cachedPropertyType = Custom;
+ }
+
+ void setCustomIndex(JSValue slotBase, unsigned index, GetIndexValueFunc getIndexValue)
+ {
+ ASSERT(slotBase);
+ ASSERT(getIndexValue);
+ m_getValue = INDEX_GETTER_MARKER;
+ m_getIndexValue = getIndexValue;
+ m_slotBase = slotBase;
+ m_data.index = index;
+ }
+
+ void setGetterSlot(JSObject* getterFunc)
+ {
+ ASSERT(getterFunc);
+ m_thisValue = m_slotBase;
+ m_getValue = GETTER_FUNCTION_MARKER;
+ m_data.getterFunc = getterFunc;
+ }
+
+ void setCacheableGetterSlot(JSValue slotBase, JSObject* getterFunc, unsigned offset)
+ {
+ ASSERT(getterFunc);
+ m_getValue = GETTER_FUNCTION_MARKER;
+ m_thisValue = m_slotBase;
+ m_slotBase = slotBase;
+ m_data.getterFunc = getterFunc;
+ m_offset = offset;
+ m_cachedPropertyType = Getter;
+ }
+
+ void setUndefined()
+ {
+ setValue(jsUndefined());
+ }
+
+ JSValue slotBase() const
+ {
+ return m_slotBase;
+ }
+
+ void setBase(JSValue base)
+ {
+ ASSERT(m_slotBase);
+ ASSERT(base);
+ m_slotBase = base;
+ }
+
+ void clearBase()
+ {
+#ifndef NDEBUG
+ m_slotBase = JSValue();
+#endif
+ }
+
+ void clearValue()
+ {
+#ifndef NDEBUG
+ m_value = JSValue();
+#endif
+ }
+
+ void clearOffset()
+ {
+ // Clear offset even in release builds, in case this PropertySlot has been used before.
+ // (For other data members, we don't need to clear anything because reuse would meaningfully overwrite them.)
+ m_offset = 0;
+ m_cachedPropertyType = Uncacheable;
+ }
+
+ unsigned index() const { return m_data.index; }
+
+ GetValueFunc customGetter() const
+ {
+ ASSERT(m_cachedPropertyType == Custom);
+ return m_getValue;
+ }
+ private:
+ JSValue functionGetter(ExecState*) const;
+
+ GetValueFunc m_getValue;
+ GetIndexValueFunc m_getIndexValue;
+
+ JSValue m_slotBase;
+ union {
+ JSObject* getterFunc;
+ unsigned index;
+ } m_data;
+
+ JSValue m_value;
+ JSValue m_thisValue;
+
+ size_t m_offset;
+ CachedPropertyType m_cachedPropertyType;
+ };
+
+} // namespace JSC
+
+#endif // PropertySlot_h
diff --git a/Source/JavaScriptCore/runtime/Protect.h b/Source/JavaScriptCore/runtime/Protect.h
new file mode 100644
index 000000000..843c9e111
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Protect.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright (C) 2004, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef Protect_h
+#define Protect_h
+
+#include "Heap.h"
+#include "JSValue.h"
+
+namespace JSC {
+
+ inline void gcProtect(JSCell* val)
+ {
+ Heap::heap(val)->protect(val);
+ }
+
+ inline void gcUnprotect(JSCell* val)
+ {
+ Heap::heap(val)->unprotect(val);
+ }
+
+ inline void gcProtectNullTolerant(JSCell* val)
+ {
+ if (val)
+ gcProtect(val);
+ }
+
+ inline void gcUnprotectNullTolerant(JSCell* val)
+ {
+ if (val)
+ gcUnprotect(val);
+ }
+
+ inline void gcProtect(JSValue value)
+ {
+ if (value && value.isCell())
+ gcProtect(value.asCell());
+ }
+
+ inline void gcUnprotect(JSValue value)
+ {
+ if (value && value.isCell())
+ gcUnprotect(value.asCell());
+ }
+
+} // namespace JSC
+
+#endif // Protect_h
diff --git a/Source/JavaScriptCore/runtime/PutPropertySlot.h b/Source/JavaScriptCore/runtime/PutPropertySlot.h
new file mode 100644
index 000000000..69d1f8bd2
--- /dev/null
+++ b/Source/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 JSFunction;
+
+ class PutPropertySlot {
+ public:
+ enum Type { Uncachable, ExistingProperty, NewProperty };
+
+ PutPropertySlot(bool isStrictMode = false)
+ : m_type(Uncachable)
+ , m_base(0)
+ , m_isStrictMode(isStrictMode)
+ {
+ }
+
+ 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 isStrictMode() const { return m_isStrictMode; }
+ bool isCacheable() const { return m_type != Uncachable; }
+ size_t cachedOffset() const {
+ ASSERT(isCacheable());
+ return m_offset;
+ }
+
+ private:
+ Type m_type;
+ JSObject* m_base;
+ size_t m_offset;
+ bool m_isStrictMode;
+ };
+
+} // namespace JSC
+
+#endif // PutPropertySlot_h
diff --git a/Source/JavaScriptCore/runtime/RegExp.cpp b/Source/JavaScriptCore/runtime/RegExp.cpp
new file mode 100644
index 000000000..0d513d2cc
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExp.cpp
@@ -0,0 +1,486 @@
+/*
+ * Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org)
+ * Copyright (c) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ * Copyright (C) 2010 Peter Varga (pvarga@inf.u-szeged.hu), University of Szeged
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "RegExp.h"
+
+#include "Lexer.h"
+#include "RegExpCache.h"
+#include "yarr/Yarr.h"
+#include "yarr/YarrJIT.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wtf/Assertions.h>
+#include <wtf/OwnArrayPtr.h>
+
+
+#define REGEXP_FUNC_TEST_DATA_GEN 0
+
+namespace JSC {
+
+const ClassInfo RegExp::s_info = { "RegExp", 0, 0, 0, CREATE_METHOD_TABLE(RegExp) };
+
+RegExpFlags regExpFlags(const UString& string)
+{
+ RegExpFlags flags = NoFlags;
+
+ for (unsigned i = 0; i < string.length(); ++i) {
+ switch (string[i]) {
+ case 'g':
+ if (flags & FlagGlobal)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagGlobal);
+ break;
+
+ case 'i':
+ if (flags & FlagIgnoreCase)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagIgnoreCase);
+ break;
+
+ case 'm':
+ if (flags & FlagMultiline)
+ return InvalidFlags;
+ flags = static_cast<RegExpFlags>(flags | FlagMultiline);
+ break;
+
+ default:
+ return InvalidFlags;
+ }
+ }
+
+ return flags;
+}
+
+#if REGEXP_FUNC_TEST_DATA_GEN
+class RegExpFunctionalTestCollector {
+ // This class is not thread safe.
+protected:
+ static const char* const s_fileName;
+
+public:
+ static RegExpFunctionalTestCollector* get();
+
+ ~RegExpFunctionalTestCollector();
+
+ void outputOneTest(RegExp*, UString, int, int*, int);
+ void clearRegExp(RegExp* regExp)
+ {
+ if (regExp == m_lastRegExp)
+ m_lastRegExp = 0;
+ }
+
+private:
+ RegExpFunctionalTestCollector();
+
+ void outputEscapedUString(const UString&, bool escapeSlash = false);
+
+ static RegExpFunctionalTestCollector* s_instance;
+ FILE* m_file;
+ RegExp* m_lastRegExp;
+};
+
+const char* const RegExpFunctionalTestCollector::s_fileName = "/tmp/RegExpTestsData";
+RegExpFunctionalTestCollector* RegExpFunctionalTestCollector::s_instance = 0;
+
+RegExpFunctionalTestCollector* RegExpFunctionalTestCollector::get()
+{
+ if (!s_instance)
+ s_instance = new RegExpFunctionalTestCollector();
+
+ return s_instance;
+}
+
+void RegExpFunctionalTestCollector::outputOneTest(RegExp* regExp, UString s, int startOffset, int* ovector, int result)
+{
+ if ((!m_lastRegExp) || (m_lastRegExp != regExp)) {
+ m_lastRegExp = regExp;
+ fputc('/', m_file);
+ outputEscapedUString(regExp->pattern(), true);
+ fputc('/', m_file);
+ if (regExp->global())
+ fputc('g', m_file);
+ if (regExp->ignoreCase())
+ fputc('i', m_file);
+ if (regExp->multiline())
+ fputc('m', m_file);
+ fprintf(m_file, "\n");
+ }
+
+ fprintf(m_file, " \"");
+ outputEscapedUString(s);
+ fprintf(m_file, "\", %d, %d, (", startOffset, result);
+ for (unsigned i = 0; i <= regExp->numSubpatterns(); i++) {
+ int subPatternBegin = ovector[i * 2];
+ int subPatternEnd = ovector[i * 2 + 1];
+ if (subPatternBegin == -1)
+ subPatternEnd = -1;
+ fprintf(m_file, "%d, %d", subPatternBegin, subPatternEnd);
+ if (i < regExp->numSubpatterns())
+ fputs(", ", m_file);
+ }
+
+ fprintf(m_file, ")\n");
+ fflush(m_file);
+}
+
+RegExpFunctionalTestCollector::RegExpFunctionalTestCollector()
+{
+ m_file = fopen(s_fileName, "r+");
+ if (!m_file)
+ m_file = fopen(s_fileName, "w+");
+
+ fseek(m_file, 0L, SEEK_END);
+}
+
+RegExpFunctionalTestCollector::~RegExpFunctionalTestCollector()
+{
+ fclose(m_file);
+ s_instance = 0;
+}
+
+void RegExpFunctionalTestCollector::outputEscapedUString(const UString& s, bool escapeSlash)
+{
+ int len = s.length();
+
+ for (int i = 0; i < len; ++i) {
+ UChar c = s[i];
+
+ switch (c) {
+ case '\0':
+ fputs("\\0", m_file);
+ break;
+ case '\a':
+ fputs("\\a", m_file);
+ break;
+ case '\b':
+ fputs("\\b", m_file);
+ break;
+ case '\f':
+ fputs("\\f", m_file);
+ break;
+ case '\n':
+ fputs("\\n", m_file);
+ break;
+ case '\r':
+ fputs("\\r", m_file);
+ break;
+ case '\t':
+ fputs("\\t", m_file);
+ break;
+ case '\v':
+ fputs("\\v", m_file);
+ break;
+ case '/':
+ if (escapeSlash)
+ fputs("\\/", m_file);
+ else
+ fputs("/", m_file);
+ break;
+ case '\"':
+ fputs("\\\"", m_file);
+ break;
+ case '\\':
+ fputs("\\\\", m_file);
+ break;
+ case '\?':
+ fputs("\?", m_file);
+ break;
+ default:
+ if (c > 0x7f)
+ fprintf(m_file, "\\u%04x", c);
+ else
+ fputc(c, m_file);
+ break;
+ }
+ }
+}
+#endif
+
+struct RegExpRepresentation {
+#if ENABLE(YARR_JIT)
+ Yarr::YarrCodeBlock m_regExpJITCode;
+#endif
+ OwnPtr<Yarr::BytecodePattern> m_regExpBytecode;
+};
+
+RegExp::RegExp(JSGlobalData& globalData, const UString& patternString, RegExpFlags flags)
+ : JSCell(globalData, globalData.regExpStructure.get())
+ , m_state(NotCompiled)
+ , m_patternString(patternString)
+ , m_flags(flags)
+ , m_constructionError(0)
+ , m_numSubpatterns(0)
+#if ENABLE(REGEXP_TRACING)
+ , m_rtMatchCallCount(0)
+ , m_rtMatchFoundCount(0)
+#endif
+{
+}
+
+void RegExp::finishCreation(JSGlobalData& globalData)
+{
+ Base::finishCreation(globalData);
+ Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
+ if (m_constructionError)
+ m_state = ParseError;
+ else
+ m_numSubpatterns = pattern.m_numSubpatterns;
+}
+
+void RegExp::destroy(JSCell* cell)
+{
+ RegExp* thisObject = jsCast<RegExp*>(cell);
+#if REGEXP_FUNC_TEST_DATA_GEN
+ RegExpFunctionalTestCollector::get()->clearRegExp(this);
+#endif
+ thisObject->RegExp::~RegExp();
+}
+
+RegExp* RegExp::createWithoutCaching(JSGlobalData& globalData, const UString& patternString, RegExpFlags flags)
+{
+ RegExp* regExp = new (NotNull, allocateCell<RegExp>(globalData.heap)) RegExp(globalData, patternString, flags);
+ regExp->finishCreation(globalData);
+ return regExp;
+}
+
+RegExp* RegExp::create(JSGlobalData& globalData, const UString& patternString, RegExpFlags flags)
+{
+ return globalData.regExpCache()->lookupOrCreate(patternString, flags);
+}
+
+void RegExp::compile(JSGlobalData* globalData, Yarr::YarrCharSize charSize)
+{
+ Yarr::YarrPattern pattern(m_patternString, ignoreCase(), multiline(), &m_constructionError);
+ if (m_constructionError) {
+ ASSERT_NOT_REACHED();
+ m_state = ParseError;
+ return;
+ }
+ ASSERT(m_numSubpatterns == pattern.m_numSubpatterns);
+
+ if (!m_representation) {
+ ASSERT(m_state == NotCompiled);
+ m_representation = adoptPtr(new RegExpRepresentation);
+ globalData->regExpCache()->addToStrongCache(this);
+ m_state = ByteCode;
+ }
+
+#if ENABLE(YARR_JIT)
+ if (!pattern.m_containsBackreferences && globalData->canUseJIT()) {
+ Yarr::jitCompile(pattern, charSize, globalData, m_representation->m_regExpJITCode);
+#if ENABLE(YARR_JIT_DEBUG)
+ if (!m_representation->m_regExpJITCode.isFallBack())
+ m_state = JITCode;
+ else
+ m_state = ByteCode;
+#else
+ if (!m_representation->m_regExpJITCode.isFallBack()) {
+ m_state = JITCode;
+ return;
+ }
+#endif
+ }
+#else
+ UNUSED_PARAM(charSize);
+#endif
+
+ m_representation->m_regExpBytecode = Yarr::byteCompile(pattern, &globalData->m_regExpAllocator);
+}
+
+void RegExp::compileIfNecessary(JSGlobalData& globalData, Yarr::YarrCharSize charSize)
+{
+ // If the state is NotCompiled or ParseError, then there is no representation.
+ // If there is a representation, and the state must be either JITCode or ByteCode.
+ ASSERT(!!m_representation == (m_state == JITCode || m_state == ByteCode));
+
+ if (m_representation) {
+#if ENABLE(YARR_JIT)
+ if (m_state != JITCode)
+ return;
+ if ((charSize == Yarr::Char8) && (m_representation->m_regExpJITCode.has8BitCode()))
+ return;
+ if ((charSize == Yarr::Char16) && (m_representation->m_regExpJITCode.has16BitCode()))
+ return;
+#else
+ return;
+#endif
+ }
+
+ compile(&globalData, charSize);
+}
+
+
+int RegExp::match(JSGlobalData& globalData, const UString& s, int startOffset, Vector<int, 32>* ovector)
+{
+ if (startOffset < 0)
+ startOffset = 0;
+
+#if ENABLE(REGEXP_TRACING)
+ m_rtMatchCallCount++;
+#endif
+
+ if (static_cast<unsigned>(startOffset) > s.length() || s.isNull())
+ return -1;
+
+ if (m_state != ParseError) {
+ compileIfNecessary(globalData, s.is8Bit() ? Yarr::Char8 : Yarr::Char16);
+
+ int offsetVectorSize = (m_numSubpatterns + 1) * 2;
+ int* offsetVector;
+ Vector<int, 32> nonReturnedOvector;
+ if (ovector) {
+ ovector->resize(offsetVectorSize);
+ offsetVector = ovector->data();
+ } else {
+ nonReturnedOvector.resize(offsetVectorSize);
+ offsetVector = nonReturnedOvector.data();
+ }
+
+ ASSERT(offsetVector);
+ // Initialize offsetVector with the return value (index 0) and the
+ // first subpattern start indicies (even index values) set to -1.
+ // No need to init the subpattern end indicies.
+ for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++)
+ offsetVector[j] = -1;
+
+ int result;
+#if ENABLE(YARR_JIT)
+ if (m_state == JITCode) {
+ if (s.is8Bit())
+ result = Yarr::execute(m_representation->m_regExpJITCode, s.characters8(), startOffset, s.length(), offsetVector);
+ else
+ result = Yarr::execute(m_representation->m_regExpJITCode, s.characters16(), startOffset, s.length(), offsetVector);
+#if ENABLE(YARR_JIT_DEBUG)
+ matchCompareWithInterpreter(s, startOffset, offsetVector, result);
+#endif
+ } else
+#endif
+ result = Yarr::interpret(m_representation->m_regExpBytecode.get(), s, startOffset, s.length(), offsetVector);
+ ASSERT(result >= -1);
+
+#if REGEXP_FUNC_TEST_DATA_GEN
+ RegExpFunctionalTestCollector::get()->outputOneTest(this, s, startOffset, offsetVector, result);
+#endif
+
+#if ENABLE(REGEXP_TRACING)
+ if (result != -1)
+ m_rtMatchFoundCount++;
+#endif
+
+ return result;
+ }
+
+ return -1;
+}
+
+void RegExp::invalidateCode()
+{
+ if (!m_representation)
+ return;
+ m_state = NotCompiled;
+ m_representation.clear();
+}
+
+#if ENABLE(YARR_JIT_DEBUG)
+void RegExp::matchCompareWithInterpreter(const UString& s, int startOffset, int* offsetVector, int jitResult)
+{
+ int offsetVectorSize = (m_numSubpatterns + 1) * 2;
+ Vector<int, 32> interpreterOvector;
+ interpreterOvector.resize(offsetVectorSize);
+ int* interpreterOffsetVector = interpreterOvector.data();
+ int interpreterResult = 0;
+ int differences = 0;
+
+ // Initialize interpreterOffsetVector with the return value (index 0) and the
+ // first subpattern start indicies (even index values) set to -1.
+ // No need to init the subpattern end indicies.
+ for (unsigned j = 0, i = 0; i < m_numSubpatterns + 1; j += 2, i++)
+ interpreterOffsetVector[j] = -1;
+
+ interpreterResult = Yarr::interpret(m_representation->m_regExpBytecode.get(), s, startOffset, s.length(), interpreterOffsetVector);
+
+ if (jitResult != interpreterResult)
+ differences++;
+
+ for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++)
+ if ((offsetVector[j] != interpreterOffsetVector[j])
+ || ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1])))
+ differences++;
+
+ if (differences) {
+ fprintf(stderr, "RegExp Discrepency for /%s/\n string input ", pattern().utf8().data());
+ unsigned segmentLen = s.length() - static_cast<unsigned>(startOffset);
+
+ fprintf(stderr, (segmentLen < 150) ? "\"%s\"\n" : "\"%148s...\"\n", s.utf8().data() + startOffset);
+
+ if (jitResult != interpreterResult) {
+ fprintf(stderr, " JIT result = %d, blah interpreted result = %d\n", jitResult, interpreterResult);
+ differences--;
+ } else {
+ fprintf(stderr, " Correct result = %d\n", jitResult);
+ }
+
+ if (differences) {
+ for (unsigned j = 2, i = 0; i < m_numSubpatterns; j +=2, i++) {
+ if (offsetVector[j] != interpreterOffsetVector[j])
+ fprintf(stderr, " JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j, offsetVector[j], j, interpreterOffsetVector[j]);
+ if ((offsetVector[j] >= 0) && (offsetVector[j+1] != interpreterOffsetVector[j+1]))
+ fprintf(stderr, " JIT offset[%d] = %d, interpreted offset[%d] = %d\n", j+1, offsetVector[j+1], j+1, interpreterOffsetVector[j+1]);
+ }
+ }
+ }
+}
+#endif
+
+#if ENABLE(REGEXP_TRACING)
+ void RegExp::printTraceData()
+ {
+ char formattedPattern[41];
+ char rawPattern[41];
+
+ strncpy(rawPattern, pattern().utf8().data(), 40);
+ rawPattern[40]= '\0';
+
+ int pattLen = strlen(rawPattern);
+
+ snprintf(formattedPattern, 41, (pattLen <= 38) ? "/%.38s/" : "/%.36s...", rawPattern);
+
+#if ENABLE(YARR_JIT)
+ Yarr::YarrCodeBlock& codeBlock = m_representation->m_regExpJITCode;
+
+ const size_t jitAddrSize = 20;
+ char jitAddr[jitAddrSize];
+ if (m_state == JITCode)
+ snprintf(jitAddr, jitAddrSize, "fallback");
+ else
+ snprintf(jitAddr, jitAddrSize, "0x%014lx", reinterpret_cast<unsigned long int>(codeBlock.getAddr()));
+#else
+ const char* jitAddr = "JIT Off";
+#endif
+
+ printf("%-40.40s %16.16s %10d %10d\n", formattedPattern, jitAddr, m_rtMatchCallCount, m_rtMatchFoundCount);
+ }
+#endif
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExp.h b/Source/JavaScriptCore/runtime/RegExp.h
new file mode 100644
index 000000000..65eb48499
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExp.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef RegExp_h
+#define RegExp_h
+
+#include "UString.h"
+#include "ExecutableAllocator.h"
+#include "Structure.h"
+#include "RegExpKey.h"
+#include "yarr/Yarr.h"
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+
+namespace JSC {
+
+ struct RegExpRepresentation;
+ class JSGlobalData;
+
+ RegExpFlags regExpFlags(const UString&);
+
+ class RegExp : public JSCell {
+ public:
+ typedef JSCell Base;
+
+ static RegExp* create(JSGlobalData&, const UString& pattern, RegExpFlags);
+ static void destroy(JSCell*);
+
+ bool global() const { return m_flags & FlagGlobal; }
+ bool ignoreCase() const { return m_flags & FlagIgnoreCase; }
+ bool multiline() const { return m_flags & FlagMultiline; }
+
+ const UString& pattern() const { return m_patternString; }
+
+ bool isValid() const { return !m_constructionError && m_flags != InvalidFlags; }
+ const char* errorMessage() const { return m_constructionError; }
+
+ int match(JSGlobalData&, const UString&, int startOffset, Vector<int, 32>* ovector = 0);
+ unsigned numSubpatterns() const { return m_numSubpatterns; }
+
+ bool hasCode()
+ {
+ return m_representation;
+ }
+
+ void invalidateCode();
+
+#if ENABLE(REGEXP_TRACING)
+ void printTraceData();
+#endif
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(LeafType, 0), &s_info);
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ RegExpKey key() { return RegExpKey(m_flags, m_patternString); }
+
+ protected:
+ void finishCreation(JSGlobalData&);
+
+ private:
+ friend class RegExpCache;
+ RegExp(JSGlobalData&, const UString&, RegExpFlags);
+
+ static RegExp* createWithoutCaching(JSGlobalData&, const UString&, RegExpFlags);
+
+ enum RegExpState {
+ ParseError,
+ JITCode,
+ ByteCode,
+ NotCompiled
+ } m_state;
+
+ void compile(JSGlobalData*, Yarr::YarrCharSize);
+ void compileIfNecessary(JSGlobalData&, Yarr::YarrCharSize);
+
+#if ENABLE(YARR_JIT_DEBUG)
+ void matchCompareWithInterpreter(const UString&, int startOffset, int* offsetVector, int jitResult);
+#endif
+
+ UString m_patternString;
+ RegExpFlags m_flags;
+ const char* m_constructionError;
+ unsigned m_numSubpatterns;
+#if ENABLE(REGEXP_TRACING)
+ unsigned m_rtMatchCallCount;
+ unsigned m_rtMatchFoundCount;
+#endif
+
+ OwnPtr<RegExpRepresentation> m_representation;
+ };
+
+} // namespace JSC
+
+#endif // RegExp_h
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.cpp b/Source/JavaScriptCore/runtime/RegExpCache.cpp
new file mode 100644
index 000000000..cd96301db
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpCache.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu)
+ * 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 UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED 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 "RegExpCache.h"
+#include "RegExpObject.h"
+#include "StrongInlines.h"
+
+namespace JSC {
+
+RegExp* RegExpCache::lookupOrCreate(const UString& patternString, RegExpFlags flags)
+{
+ RegExpKey key(flags, patternString);
+ RegExpCacheMap::iterator result = m_weakCache.find(key);
+ if (result != m_weakCache.end())
+ return result->second.get();
+ RegExp* regExp = RegExp::createWithoutCaching(*m_globalData, patternString, flags);
+#if ENABLE(REGEXP_TRACING)
+ m_globalData->addRegExpToTrace(regExp);
+#endif
+ // We need to do a second lookup to add the RegExp as
+ // allocating it may have caused a gc cycle, which in
+ // turn may have removed items from the cache.
+ m_weakCache.add(key, Weak<RegExp>(*m_globalData, regExp, this));
+ return regExp;
+}
+
+RegExpCache::RegExpCache(JSGlobalData* globalData)
+ : m_nextEntryInStrongCache(0)
+ , m_globalData(globalData)
+{
+}
+
+void RegExpCache::finalize(Handle<Unknown> handle, void*)
+{
+ RegExp* regExp = static_cast<RegExp*>(handle.get().asCell());
+ m_weakCache.remove(regExp->key());
+ regExp->invalidateCode();
+}
+
+void RegExpCache::addToStrongCache(RegExp* regExp)
+{
+ UString pattern = regExp->pattern();
+ if (pattern.length() > maxStrongCacheablePatternLength)
+ return;
+ m_strongCache[m_nextEntryInStrongCache].set(*m_globalData, regExp);
+ m_nextEntryInStrongCache++;
+ if (m_nextEntryInStrongCache == maxStrongCacheableEntries)
+ m_nextEntryInStrongCache = 0;
+}
+
+void RegExpCache::invalidateCode()
+{
+ for (int i = 0; i < maxStrongCacheableEntries; i++)
+ m_strongCache[i].clear();
+ m_nextEntryInStrongCache = 0;
+ RegExpCacheMap::iterator end = m_weakCache.end();
+ for (RegExpCacheMap::iterator ptr = m_weakCache.begin(); ptr != end; ++ptr)
+ ptr->second->invalidateCode();
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/RegExpCache.h b/Source/JavaScriptCore/runtime/RegExpCache.h
new file mode 100644
index 000000000..4f3ea1536
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpCache.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu)
+ * 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 UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED 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 "RegExp.h"
+#include "RegExpKey.h"
+#include "Strong.h"
+#include "UString.h"
+#include "Weak.h"
+#include <wtf/FixedArray.h>
+#include <wtf/HashMap.h>
+
+#ifndef RegExpCache_h
+#define RegExpCache_h
+
+namespace JSC {
+
+class RegExpCache : private WeakHandleOwner {
+friend class RegExp;
+typedef HashMap<RegExpKey, Weak<RegExp> > RegExpCacheMap;
+
+public:
+ RegExpCache(JSGlobalData* globalData);
+ void invalidateCode();
+
+private:
+
+ static const unsigned maxStrongCacheablePatternLength = 256;
+
+ static const int maxStrongCacheableEntries = 32;
+
+ virtual void finalize(Handle<Unknown>, void* context);
+
+ RegExp* lookupOrCreate(const UString& patternString, RegExpFlags);
+ void addToStrongCache(RegExp*);
+ RegExpCacheMap m_weakCache; // Holds all regular expressions currently live.
+ int m_nextEntryInStrongCache;
+ WTF::FixedArray<Strong<RegExp>, maxStrongCacheableEntries> m_strongCache; // Holds a select few regular expressions that have compiled and executed
+ JSGlobalData* m_globalData;
+};
+
+} // namespace JSC
+
+#endif // RegExpCache_h
diff --git a/Source/JavaScriptCore/runtime/RegExpConstructor.cpp b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
new file mode 100644
index 000000000..05832ed0c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.cpp
@@ -0,0 +1,400 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "RegExpConstructor.h"
+
+#include "ArrayPrototype.h"
+#include "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSArray.h"
+#include "JSFunction.h"
+#include "JSString.h"
+#include "Lookup.h"
+#include "ObjectPrototype.h"
+#include "RegExpMatchesArray.h"
+#include "RegExpObject.h"
+#include "RegExpPrototype.h"
+#include "RegExp.h"
+#include "RegExpCache.h"
+#include "UStringConcatenate.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace JSC {
+
+static JSValue regExpConstructorInput(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorMultiline(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorLastMatch(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorLastParen(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorLeftContext(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorRightContext(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorDollar1(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorDollar2(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorDollar3(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorDollar4(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorDollar5(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorDollar6(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorDollar7(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorDollar8(ExecState*, JSValue, const Identifier&);
+static JSValue regExpConstructorDollar9(ExecState*, JSValue, const Identifier&);
+
+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::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::regExpConstructorTable, CREATE_METHOD_TABLE(RegExpConstructor) };
+
+const ClassInfo RegExpMatchesArray::s_info = {"Array", &JSArray::s_info, 0, 0, CREATE_METHOD_TABLE(RegExpMatchesArray)};
+
+/* 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
+*/
+
+RegExpConstructor::RegExpConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+ , d(adoptPtr(new RegExpConstructorPrivate))
+{
+}
+
+void RegExpConstructor::finishCreation(ExecState* exec, RegExpPrototype* regExpPrototype)
+{
+ Base::finishCreation(exec->globalData(), Identifier(exec, "RegExp"));
+ ASSERT(inherits(&s_info));
+
+ // ECMA 15.10.5.1 RegExp.prototype
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, regExpPrototype, DontEnum | DontDelete | ReadOnly);
+
+ // no. of arguments for constructor
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(2), ReadOnly | DontDelete | DontEnum);
+}
+
+void RegExpConstructor::destroy(JSCell* cell)
+{
+ jsCast<RegExpConstructor*>(cell)->RegExpConstructor::~RegExpConstructor();
+}
+
+RegExpMatchesArray::RegExpMatchesArray(ExecState* exec)
+ : JSArray(exec->globalData(), exec->lexicalGlobalObject()->regExpMatchesArrayStructure())
+{
+}
+
+void RegExpMatchesArray::finishCreation(JSGlobalData& globalData, RegExpConstructorPrivate* data)
+{
+ Base::finishCreation(globalData, data->lastNumSubPatterns + 1);
+ RegExpConstructorPrivate* d = new RegExpConstructorPrivate;
+ d->input = data->lastInput;
+ d->lastInput = data->lastInput;
+ d->lastNumSubPatterns = data->lastNumSubPatterns;
+ unsigned offsetVectorSize = (data->lastNumSubPatterns + 1) * 2; // only copying the result part of the vector
+ d->lastOvector().resize(offsetVectorSize);
+ memcpy(d->lastOvector().data(), data->lastOvector().data(), offsetVectorSize * sizeof(int));
+ // d->multiline is not needed, and remains uninitialized
+
+ setSubclassData(d);
+}
+
+RegExpMatchesArray::~RegExpMatchesArray()
+{
+ delete static_cast<RegExpConstructorPrivate*>(subclassData());
+}
+
+void RegExpMatchesArray::destroy(JSCell* cell)
+{
+ jsCast<RegExpMatchesArray*>(cell)->RegExpMatchesArray::~RegExpMatchesArray();
+}
+
+void RegExpMatchesArray::fillArrayInstance(ExecState* exec)
+{
+ RegExpConstructorPrivate* d = static_cast<RegExpConstructorPrivate*>(subclassData());
+ ASSERT(d);
+
+ unsigned lastNumSubpatterns = d->lastNumSubPatterns;
+
+ for (unsigned i = 0; i <= lastNumSubpatterns; ++i) {
+ int start = d->lastOvector()[2 * i];
+ if (start >= 0)
+ JSArray::putByIndex(this, exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start));
+ else
+ JSArray::putByIndex(this, exec, i, jsUndefined());
+ }
+
+ PutPropertySlot slot;
+ JSArray::put(this, exec, exec->propertyNames().index, jsNumber(d->lastOvector()[0]), slot);
+ JSArray::put(this, exec, exec->propertyNames().input, jsString(exec, d->input), slot);
+
+ delete d;
+ setSubclassData(0);
+}
+
+JSObject* RegExpConstructor::arrayOfMatches(ExecState* exec) const
+{
+ return RegExpMatchesArray::create(exec, d.get());
+}
+
+JSValue RegExpConstructor::getBackref(ExecState* exec, unsigned i) const
+{
+ if (!d->lastOvector().isEmpty() && i <= d->lastNumSubPatterns) {
+ int start = d->lastOvector()[2 * i];
+ if (start >= 0)
+ return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start);
+ }
+ return jsEmptyString(exec);
+}
+
+JSValue RegExpConstructor::getLastParen(ExecState* exec) const
+{
+ unsigned i = d->lastNumSubPatterns;
+ if (i > 0) {
+ ASSERT(!d->lastOvector().isEmpty());
+ int start = d->lastOvector()[2 * i];
+ if (start >= 0)
+ return jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start);
+ }
+ return jsEmptyString(exec);
+}
+
+JSValue RegExpConstructor::getLeftContext(ExecState* exec) const
+{
+ if (!d->lastOvector().isEmpty())
+ return jsSubstring(exec, d->lastInput, 0, d->lastOvector()[0]);
+ return jsEmptyString(exec);
+}
+
+JSValue RegExpConstructor::getRightContext(ExecState* exec) const
+{
+ if (!d->lastOvector().isEmpty())
+ return jsSubstring(exec, d->lastInput, d->lastOvector()[1], d->lastInput.length() - d->lastOvector()[1]);
+ return jsEmptyString(exec);
+}
+
+bool RegExpConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(cell), propertyName, slot);
+}
+
+bool RegExpConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticValueDescriptor<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(object), propertyName, descriptor);
+}
+
+JSValue regExpConstructorDollar1(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 1);
+}
+
+JSValue regExpConstructorDollar2(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 2);
+}
+
+JSValue regExpConstructorDollar3(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 3);
+}
+
+JSValue regExpConstructorDollar4(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 4);
+}
+
+JSValue regExpConstructorDollar5(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 5);
+}
+
+JSValue regExpConstructorDollar6(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 6);
+}
+
+JSValue regExpConstructorDollar7(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 7);
+}
+
+JSValue regExpConstructorDollar8(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 8);
+}
+
+JSValue regExpConstructorDollar9(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 9);
+}
+
+JSValue regExpConstructorInput(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return jsString(exec, asRegExpConstructor(slotBase)->input());
+}
+
+JSValue regExpConstructorMultiline(ExecState*, JSValue slotBase, const Identifier&)
+{
+ return jsBoolean(asRegExpConstructor(slotBase)->multiline());
+}
+
+JSValue regExpConstructorLastMatch(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getBackref(exec, 0);
+}
+
+JSValue regExpConstructorLastParen(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getLastParen(exec);
+}
+
+JSValue regExpConstructorLeftContext(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getLeftContext(exec);
+}
+
+JSValue regExpConstructorRightContext(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ return asRegExpConstructor(slotBase)->getRightContext(exec);
+}
+
+void RegExpConstructor::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ lookupPut<RegExpConstructor, InternalFunction>(exec, propertyName, value, ExecState::regExpConstructorTable(exec), jsCast<RegExpConstructor*>(cell), 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, JSGlobalObject* globalObject, const ArgList& args, bool callAsConstructor)
+{
+ JSValue arg0 = args.at(0);
+ JSValue arg1 = args.at(1);
+
+ if (arg0.inherits(&RegExpObject::s_info)) {
+ if (!arg1.isUndefined())
+ return throwError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another."));
+ // If called as a function, this just returns the first argument (see 15.10.3.1).
+ if (callAsConstructor) {
+ RegExp* regExp = static_cast<RegExpObject*>(asObject(arg0))->regExp();
+ return RegExpObject::create(exec, globalObject, globalObject->regExpStructure(), regExp);
+ }
+ return asObject(arg0);
+ }
+
+ UString pattern = arg0.isUndefined() ? UString("") : arg0.toString(exec);
+ if (exec->hadException())
+ return 0;
+
+ RegExpFlags flags = NoFlags;
+ if (!arg1.isUndefined()) {
+ flags = regExpFlags(arg1.toString(exec));
+ if (exec->hadException())
+ return 0;
+ if (flags == InvalidFlags)
+ return throwError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
+ }
+
+ RegExp* regExp = RegExp::create(exec->globalData(), pattern, flags);
+ if (!regExp->isValid())
+ return throwError(exec, createSyntaxError(exec, regExp->errorMessage()));
+ return RegExpObject::create(exec, exec->lexicalGlobalObject(), globalObject->regExpStructure(), regExp);
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWithRegExpConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args, true));
+}
+
+ConstructType RegExpConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithRegExpConstructor;
+ return ConstructTypeHost;
+}
+
+// ECMA 15.10.3
+static EncodedJSValue JSC_HOST_CALL callRegExpConstructor(ExecState* exec)
+{
+ ArgList args(exec);
+ return JSValue::encode(constructRegExp(exec, asInternalFunction(exec->callee())->globalObject(), args));
+}
+
+CallType RegExpConstructor::getCallData(JSCell*, 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/Source/JavaScriptCore/runtime/RegExpConstructor.h b/Source/JavaScriptCore/runtime/RegExpConstructor.h
new file mode 100644
index 000000000..0a43da70a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpConstructor.h
@@ -0,0 +1,144 @@
+/*
+ * 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 "RegExp.h"
+#include <wtf/OwnPtr.h>
+
+namespace JSC {
+
+ class RegExp;
+ class RegExpPrototype;
+ struct RegExpConstructorPrivate;
+
+ struct RegExpConstructorPrivate {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ // Global search cache / settings
+ RegExpConstructorPrivate()
+ : lastNumSubPatterns(0)
+ , multiline(false)
+ , lastOvectorIndex(0)
+ {
+ }
+
+ const Vector<int, 32>& lastOvector() const { return ovector[lastOvectorIndex]; }
+ Vector<int, 32>& lastOvector() { return ovector[lastOvectorIndex]; }
+ Vector<int, 32>& tempOvector() { return ovector[lastOvectorIndex ? 0 : 1]; }
+ void changeLastOvector() { lastOvectorIndex = lastOvectorIndex ? 0 : 1; }
+
+ UString input;
+ UString lastInput;
+ Vector<int, 32> ovector[2];
+ unsigned lastNumSubPatterns : 30;
+ bool multiline : 1;
+ unsigned lastOvectorIndex : 1;
+ };
+
+ class RegExpConstructor : public InternalFunction {
+ public:
+ typedef InternalFunction Base;
+
+ static RegExpConstructor* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, RegExpPrototype* regExpPrototype)
+ {
+ RegExpConstructor* constructor = new (NotNull, allocateCell<RegExpConstructor>(*exec->heap())) RegExpConstructor(globalObject, structure);
+ constructor->finishCreation(exec, regExpPrototype);
+ return constructor;
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static const ClassInfo s_info;
+
+ void performMatch(JSGlobalData&, 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;
+
+ protected:
+ void finishCreation(ExecState*, RegExpPrototype*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | InternalFunction::StructureFlags;
+
+ private:
+ RegExpConstructor(JSGlobalObject*, Structure*);
+ static void destroy(JSCell*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+
+ OwnPtr<RegExpConstructorPrivate> d;
+ };
+
+ RegExpConstructor* asRegExpConstructor(JSValue);
+
+ JSObject* constructRegExp(ExecState*, JSGlobalObject*, const ArgList&, bool callAsConstructor = false);
+
+ inline RegExpConstructor* asRegExpConstructor(JSValue value)
+ {
+ ASSERT(asObject(value)->inherits(&RegExpConstructor::s_info));
+ return static_cast<RegExpConstructor*>(asObject(value));
+ }
+
+ /*
+ To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular
+ expression matching through the performMatch function. We use cached results to calculate,
+ e.g., RegExp.lastMatch and RegExp.leftParen.
+ */
+ ALWAYS_INLINE void RegExpConstructor::performMatch(JSGlobalData& globalData, RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
+ {
+ position = r->match(globalData, s, startOffset, &d->tempOvector());
+
+ if (ovector)
+ *ovector = d->tempOvector().data();
+
+ if (position != -1) {
+ ASSERT(!d->tempOvector().isEmpty());
+
+ length = d->tempOvector()[1] - d->tempOvector()[0];
+
+ d->input = s;
+ d->lastInput = s;
+ d->changeLastOvector();
+ d->lastNumSubPatterns = r->numSubpatterns();
+ }
+ }
+
+} // namespace JSC
+
+#endif // RegExpConstructor_h
diff --git a/Source/JavaScriptCore/runtime/RegExpKey.h b/Source/JavaScriptCore/runtime/RegExpKey.h
new file mode 100644
index 000000000..b4847f971
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpKey.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2010 University of Szeged
+ * Copyright (C) 2010 Renata Hodovan (hodovan@inf.u-szeged.hu)
+ * 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 UNIVERSITY OF SZEGED ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED 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 RegExpKey_h
+#define RegExpKey_h
+
+#include "UString.h"
+#include <wtf/text/StringHash.h>
+
+namespace JSC {
+
+enum RegExpFlags {
+ NoFlags = 0,
+ FlagGlobal = 1,
+ FlagIgnoreCase = 2,
+ FlagMultiline = 4,
+ InvalidFlags = 8,
+ DeletedValueFlags = -1
+};
+
+struct RegExpKey {
+ RegExpFlags flagsValue;
+ RefPtr<StringImpl> pattern;
+
+ RegExpKey()
+ : flagsValue(NoFlags)
+ {
+ }
+
+ RegExpKey(RegExpFlags flags)
+ : flagsValue(flags)
+ {
+ }
+
+ RegExpKey(RegExpFlags flags, const UString& pattern)
+ : flagsValue(flags)
+ , pattern(pattern.impl())
+ {
+ }
+
+ RegExpKey(RegExpFlags flags, const PassRefPtr<StringImpl> pattern)
+ : flagsValue(flags)
+ , pattern(pattern)
+ {
+ }
+
+ RegExpKey(RegExpFlags flags, const RefPtr<StringImpl>& pattern)
+ : flagsValue(flags)
+ , pattern(pattern)
+ {
+ }
+};
+
+inline bool operator==(const RegExpKey& a, const RegExpKey& b)
+{
+ if (a.flagsValue != b.flagsValue)
+ return false;
+ if (!a.pattern)
+ return !b.pattern;
+ if (!b.pattern)
+ return false;
+ return equal(a.pattern.get(), b.pattern.get());
+}
+
+} // namespace JSC
+
+namespace WTF {
+template<typename T> struct DefaultHash;
+template<typename T> struct RegExpHash;
+
+template<> struct RegExpHash<JSC::RegExpKey> {
+ static unsigned hash(const JSC::RegExpKey& key) { return key.pattern->hash(); }
+ static bool equal(const JSC::RegExpKey& a, const JSC::RegExpKey& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+template<> struct DefaultHash<JSC::RegExpKey> {
+ typedef RegExpHash<JSC::RegExpKey> Hash;
+};
+
+template<> struct HashTraits<JSC::RegExpKey> : GenericHashTraits<JSC::RegExpKey> {
+ static void constructDeletedValue(JSC::RegExpKey& slot) { slot.flagsValue = JSC::DeletedValueFlags; }
+ static bool isDeletedValue(const JSC::RegExpKey& value) { return value.flagsValue == JSC::DeletedValueFlags; }
+};
+} // namespace WTF
+
+#endif // RegExpKey_h
diff --git a/Source/JavaScriptCore/runtime/RegExpMatchesArray.h b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h
new file mode 100644
index 000000000..a0a8a8e98
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpMatchesArray.h
@@ -0,0 +1,123 @@
+/*
+ * 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 {
+ private:
+ RegExpMatchesArray(ExecState*);
+
+ public:
+ typedef JSArray Base;
+
+ static RegExpMatchesArray* create(ExecState* exec, RegExpConstructorPrivate* ctorPrivate)
+ {
+ RegExpMatchesArray* regExp = new (NotNull, allocateCell<RegExpMatchesArray>(*exec->heap())) RegExpMatchesArray(exec);
+ regExp->finishCreation(exec->globalData(), ctorPrivate);
+ return regExp;
+ }
+ ~RegExpMatchesArray();
+ static void destroy(JSCell*);
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(JSGlobalData&, RegExpConstructorPrivate* data);
+
+ private:
+ static bool getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+ {
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
+ if (thisObject->subclassData())
+ thisObject->fillArrayInstance(exec);
+ return JSArray::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+ }
+
+ static bool getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
+ {
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
+ if (thisObject->subclassData())
+ thisObject->fillArrayInstance(exec);
+ return JSArray::getOwnPropertySlotByIndex(thisObject, exec, propertyName, slot);
+ }
+
+ static bool getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+ {
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
+ if (thisObject->subclassData())
+ thisObject->fillArrayInstance(exec);
+ return JSArray::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+ }
+
+ static void put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue v, PutPropertySlot& slot)
+ {
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
+ if (thisObject->subclassData())
+ thisObject->fillArrayInstance(exec);
+ JSArray::put(thisObject, exec, propertyName, v, slot);
+ }
+
+ static void putByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, JSValue v)
+ {
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
+ if (thisObject->subclassData())
+ thisObject->fillArrayInstance(exec);
+ JSArray::putByIndex(thisObject, exec, propertyName, v);
+ }
+
+ static bool deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
+ {
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
+ if (thisObject->subclassData())
+ thisObject->fillArrayInstance(exec);
+ return JSArray::deleteProperty(thisObject, exec, propertyName);
+ }
+
+ static bool deletePropertyByIndex(JSCell* cell, ExecState* exec, unsigned propertyName)
+ {
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(cell);
+ if (thisObject->subclassData())
+ thisObject->fillArrayInstance(exec);
+ return JSArray::deletePropertyByIndex(thisObject, exec, propertyName);
+ }
+
+ static void getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& arr, EnumerationMode mode = ExcludeDontEnumProperties)
+ {
+ RegExpMatchesArray* thisObject = jsCast<RegExpMatchesArray*>(object);
+ if (thisObject->subclassData())
+ thisObject->fillArrayInstance(exec);
+ JSArray::getOwnPropertyNames(thisObject, exec, arr, mode);
+ }
+
+ void fillArrayInstance(ExecState*);
+};
+
+}
+
+#endif // RegExpMatchesArray_h
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.cpp b/Source/JavaScriptCore/runtime/RegExpObject.cpp
new file mode 100644
index 000000000..4553f7ad0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpObject.cpp
@@ -0,0 +1,272 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008 Apple Inc. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "RegExpObject.h"
+
+#include "Error.h"
+#include "ExceptionHelpers.h"
+#include "JSArray.h"
+#include "JSGlobalObject.h"
+#include "JSString.h"
+#include "Lexer.h"
+#include "Lookup.h"
+#include "RegExpConstructor.h"
+#include "RegExpPrototype.h"
+#include "UStringBuilder.h"
+#include "UStringConcatenate.h"
+#include <wtf/PassOwnPtr.h>
+
+namespace JSC {
+
+static JSValue regExpObjectGlobal(ExecState*, JSValue, const Identifier&);
+static JSValue regExpObjectIgnoreCase(ExecState*, JSValue, const Identifier&);
+static JSValue regExpObjectMultiline(ExecState*, JSValue, const Identifier&);
+static JSValue regExpObjectSource(ExecState*, JSValue, const Identifier&);
+static JSValue regExpObjectLastIndex(ExecState*, JSValue, const Identifier&);
+static void setRegExpObjectLastIndex(ExecState*, JSObject*, JSValue);
+
+} // namespace JSC
+
+#include "RegExpObject.lut.h"
+
+namespace JSC {
+
+ASSERT_CLASS_FITS_IN_CELL(RegExpObject);
+
+const ClassInfo RegExpObject::s_info = { "RegExp", &JSNonFinalObject::s_info, 0, ExecState::regExpTable, CREATE_METHOD_TABLE(RegExpObject) };
+
+/* Source for RegExpObject.lut.h
+@begin regExpTable
+ global regExpObjectGlobal DontDelete|ReadOnly|DontEnum
+ ignoreCase regExpObjectIgnoreCase DontDelete|ReadOnly|DontEnum
+ multiline regExpObjectMultiline DontDelete|ReadOnly|DontEnum
+ source regExpObjectSource DontDelete|ReadOnly|DontEnum
+ lastIndex regExpObjectLastIndex DontDelete|DontEnum
+@end
+*/
+
+RegExpObject::RegExpObject(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
+ : JSNonFinalObject(globalObject->globalData(), structure)
+ , d(adoptPtr(new RegExpObjectData(globalObject->globalData(), this, regExp)))
+{
+}
+
+void RegExpObject::finishCreation(JSGlobalObject* globalObject)
+{
+ Base::finishCreation(globalObject->globalData());
+ ASSERT(inherits(&s_info));
+}
+
+void RegExpObject::destroy(JSCell* cell)
+{
+ jsCast<RegExpObject*>(cell)->RegExpObject::~RegExpObject();
+}
+
+void RegExpObject::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ RegExpObject* thisObject = jsCast<RegExpObject*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ Base::visitChildren(thisObject, visitor);
+ if (thisObject->d->regExp)
+ visitor.append(&thisObject->d->regExp);
+ if (UNLIKELY(!thisObject->d->lastIndex.get().isInt32()))
+ visitor.append(&thisObject->d->lastIndex);
+}
+
+bool RegExpObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), propertyName, slot);
+}
+
+bool RegExpObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), jsCast<RegExpObject*>(object), propertyName, descriptor);
+}
+
+JSValue regExpObjectGlobal(ExecState*, JSValue slotBase, const Identifier&)
+{
+ return jsBoolean(asRegExpObject(slotBase)->regExp()->global());
+}
+
+JSValue regExpObjectIgnoreCase(ExecState*, JSValue slotBase, const Identifier&)
+{
+ return jsBoolean(asRegExpObject(slotBase)->regExp()->ignoreCase());
+}
+
+JSValue regExpObjectMultiline(ExecState*, JSValue slotBase, const Identifier&)
+{
+ return jsBoolean(asRegExpObject(slotBase)->regExp()->multiline());
+}
+
+JSValue regExpObjectSource(ExecState* exec, JSValue slotBase, const Identifier&)
+{
+ UString pattern = asRegExpObject(slotBase)->regExp()->pattern();
+ unsigned length = pattern.length();
+ const UChar* characters = pattern.characters();
+ bool previousCharacterWasBackslash = false;
+ bool inBrackets = false;
+ bool shouldEscape = false;
+
+ // early return for strings that don't contain a forwards slash and LineTerminator
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ if (!previousCharacterWasBackslash) {
+ if (inBrackets) {
+ if (ch == ']')
+ inBrackets = false;
+ } else {
+ if (ch == '/') {
+ shouldEscape = true;
+ break;
+ }
+ if (ch == '[')
+ inBrackets = true;
+ }
+ }
+
+ if (Lexer<UChar>::isLineTerminator(ch)) {
+ shouldEscape = true;
+ break;
+ }
+
+ if (previousCharacterWasBackslash)
+ previousCharacterWasBackslash = false;
+ else
+ previousCharacterWasBackslash = ch == '\\';
+ }
+
+ if (!shouldEscape)
+ return jsString(exec, pattern);
+
+ previousCharacterWasBackslash = false;
+ inBrackets = false;
+ UStringBuilder result;
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ if (!previousCharacterWasBackslash) {
+ if (inBrackets) {
+ if (ch == ']')
+ inBrackets = false;
+ } else {
+ if (ch == '/')
+ result.append('\\');
+ else if (ch == '[')
+ inBrackets = true;
+ }
+ }
+
+ // escape LineTerminator
+ if (Lexer<UChar>::isLineTerminator(ch)) {
+ if (!previousCharacterWasBackslash)
+ result.append('\\');
+
+ if (ch == '\n')
+ result.append('n');
+ else if (ch == '\r')
+ result.append('r');
+ else if (ch == 0x2028)
+ result.append("u2028");
+ else
+ result.append("u2029");
+ } else
+ result.append(ch);
+
+ if (previousCharacterWasBackslash)
+ previousCharacterWasBackslash = false;
+ else
+ previousCharacterWasBackslash = ch == '\\';
+ }
+
+ return jsString(exec, result.toUString());
+}
+
+JSValue regExpObjectLastIndex(ExecState*, JSValue slotBase, const Identifier&)
+{
+ return asRegExpObject(slotBase)->getLastIndex();
+}
+
+void RegExpObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ lookupPut<RegExpObject, JSObject>(exec, propertyName, value, ExecState::regExpTable(exec), jsCast<RegExpObject*>(cell), slot);
+}
+
+void setRegExpObjectLastIndex(ExecState* exec, JSObject* baseObject, JSValue value)
+{
+ asRegExpObject(baseObject)->setLastIndex(exec->globalData(), value);
+}
+
+JSValue RegExpObject::test(ExecState* exec)
+{
+ return jsBoolean(match(exec));
+}
+
+JSValue RegExpObject::exec(ExecState* exec)
+{
+ if (match(exec))
+ return exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec);
+ return jsNull();
+}
+
+// Shared implementation used by test and exec.
+bool RegExpObject::match(ExecState* exec)
+{
+ RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
+ UString input = exec->argument(0).toString(exec);
+ JSGlobalData* globalData = &exec->globalData();
+ if (!regExp()->global()) {
+ int position;
+ int length;
+ regExpConstructor->performMatch(*globalData, d->regExp.get(), input, 0, position, length);
+ return position >= 0;
+ }
+
+ JSValue jsLastIndex = getLastIndex();
+ unsigned lastIndex;
+ if (LIKELY(jsLastIndex.isUInt32())) {
+ lastIndex = jsLastIndex.asUInt32();
+ if (lastIndex > input.length()) {
+ setLastIndex(0);
+ return false;
+ }
+ } else {
+ double doubleLastIndex = jsLastIndex.toInteger(exec);
+ if (doubleLastIndex < 0 || doubleLastIndex > input.length()) {
+ setLastIndex(0);
+ return false;
+ }
+ lastIndex = static_cast<unsigned>(doubleLastIndex);
+ }
+
+ int position;
+ int length = 0;
+ regExpConstructor->performMatch(*globalData, d->regExp.get(), input, lastIndex, position, length);
+ if (position < 0) {
+ setLastIndex(0);
+ return false;
+ }
+
+ setLastIndex(position + length);
+ return true;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpObject.h b/Source/JavaScriptCore/runtime/RegExpObject.h
new file mode 100644
index 000000000..4e84d3831
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpObject.h
@@ -0,0 +1,117 @@
+/*
+ * 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 JSNonFinalObject {
+ public:
+ typedef JSNonFinalObject Base;
+
+ static RegExpObject* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
+ {
+ RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(*exec->heap())) RegExpObject(globalObject, structure, regExp);
+ object->finishCreation(globalObject);
+ return object;
+ }
+
+ static RegExpObject* create(JSGlobalData& globalData, JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
+ {
+ RegExpObject* object = new (NotNull, allocateCell<RegExpObject>(globalData.heap)) RegExpObject(globalObject, structure, regExp);
+ object->finishCreation(globalObject);
+ return object;
+ }
+
+ void setRegExp(JSGlobalData& globalData, RegExp* r) { d->regExp.set(globalData, this, r); }
+ RegExp* regExp() const { return d->regExp.get(); }
+
+ void setLastIndex(size_t lastIndex)
+ {
+ d->lastIndex.setWithoutWriteBarrier(jsNumber(lastIndex));
+ }
+ void setLastIndex(JSGlobalData& globalData, JSValue lastIndex)
+ {
+ d->lastIndex.set(globalData, this, lastIndex);
+ }
+ JSValue getLastIndex() const
+ {
+ return d->lastIndex.get();
+ }
+
+ JSValue test(ExecState*);
+ JSValue exec(ExecState*);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ RegExpObject(JSGlobalObject*, Structure*, RegExp*);
+ void finishCreation(JSGlobalObject*);
+ static void destroy(JSCell*);
+
+ static const unsigned StructureFlags = OverridesVisitChildren | OverridesGetOwnPropertySlot | Base::StructureFlags;
+
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ private:
+ bool match(ExecState*);
+
+ struct RegExpObjectData {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ RegExpObjectData(JSGlobalData& globalData, RegExpObject* owner, RegExp* regExp)
+ : regExp(globalData, owner, regExp)
+ {
+ lastIndex.setWithoutWriteBarrier(jsNumber(0));
+ }
+
+ WriteBarrier<RegExp> regExp;
+ WriteBarrier<Unknown> lastIndex;
+ };
+#if COMPILER(MSVC)
+ friend void WTF::deleteOwnedPtr<RegExpObjectData>(RegExpObjectData*);
+#endif
+ OwnPtr<RegExpObjectData> d;
+ };
+
+ RegExpObject* asRegExpObject(JSValue);
+
+ inline RegExpObject* asRegExpObject(JSValue value)
+ {
+ ASSERT(asObject(value)->inherits(&RegExpObject::s_info));
+ return static_cast<RegExpObject*>(asObject(value));
+ }
+
+} // namespace JSC
+
+#endif // RegExpObject_h
diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.cpp b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
new file mode 100644
index 000000000..6c79f9428
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpPrototype.cpp
@@ -0,0 +1,161 @@
+/*
+ * 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 "Error.h"
+#include "JSArray.h"
+#include "JSFunction.h"
+#include "JSObject.h"
+#include "JSString.h"
+#include "JSStringBuilder.h"
+#include "JSValue.h"
+#include "ObjectPrototype.h"
+#include "RegExpObject.h"
+#include "RegExp.h"
+#include "RegExpCache.h"
+#include "StringRecursionChecker.h"
+#include "UStringConcatenate.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState*);
+static EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*);
+
+}
+
+#include "RegExpPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo RegExpPrototype::s_info = { "RegExp", &RegExpObject::s_info, 0, ExecState::regExpPrototypeTable, CREATE_METHOD_TABLE(RegExpPrototype) };
+
+/* Source for RegExpPrototype.lut.h
+@begin regExpPrototypeTable
+ compile regExpProtoFuncCompile DontEnum|Function 2
+ exec regExpProtoFuncExec DontEnum|Function 1
+ test regExpProtoFuncTest DontEnum|Function 1
+ toString regExpProtoFuncToString DontEnum|Function 0
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(RegExpPrototype);
+
+RegExpPrototype::RegExpPrototype(JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
+ : RegExpObject(globalObject, structure, regExp)
+{
+}
+
+bool RegExpPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<RegExpObject>(exec, ExecState::regExpPrototypeTable(exec), jsCast<RegExpPrototype*>(cell), propertyName, slot);
+}
+
+bool RegExpPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<RegExpObject>(exec, ExecState::regExpPrototypeTable(exec), jsCast<RegExpPrototype*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Functions ---------------------------
+
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&RegExpObject::s_info))
+ return throwVMTypeError(exec);
+ return JSValue::encode(asRegExpObject(thisValue)->test(exec));
+}
+
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&RegExpObject::s_info))
+ return throwVMTypeError(exec);
+ return JSValue::encode(asRegExpObject(thisValue)->exec(exec));
+}
+
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&RegExpObject::s_info))
+ return throwVMTypeError(exec);
+
+ RegExp* regExp;
+ JSValue arg0 = exec->argument(0);
+ JSValue arg1 = exec->argument(1);
+
+ if (arg0.inherits(&RegExpObject::s_info)) {
+ if (!arg1.isUndefined())
+ return throwVMError(exec, createTypeError(exec, "Cannot supply flags when constructing one RegExp from another."));
+ regExp = asRegExpObject(arg0)->regExp();
+ } else {
+ UString pattern = !exec->argumentCount() ? UString("") : arg0.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ RegExpFlags flags = NoFlags;
+ if (!arg1.isUndefined()) {
+ flags = regExpFlags(arg1.toString(exec));
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ if (flags == InvalidFlags)
+ return throwVMError(exec, createSyntaxError(exec, "Invalid flags supplied to RegExp constructor."));
+ }
+ regExp = RegExp::create(exec->globalData(), pattern, flags);
+ }
+
+ if (!regExp->isValid())
+ return throwVMError(exec, createSyntaxError(exec, regExp->errorMessage()));
+
+ asRegExpObject(thisValue)->setRegExp(exec->globalData(), regExp);
+ asRegExpObject(thisValue)->setLastIndex(0);
+ return JSValue::encode(jsUndefined());
+}
+
+EncodedJSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.inherits(&RegExpObject::s_info))
+ return throwVMTypeError(exec);
+
+ RegExpObject* thisObject = asRegExpObject(thisValue);
+
+ StringRecursionChecker checker(exec, thisObject);
+ if (JSValue earlyReturnValue = checker.earlyReturnValue())
+ return JSValue::encode(earlyReturnValue);
+
+ char postfix[5] = { '/', 0, 0, 0, 0 };
+ int index = 1;
+ if (thisObject->get(exec, exec->propertyNames().global).toBoolean(exec))
+ postfix[index++] = 'g';
+ if (thisObject->get(exec, exec->propertyNames().ignoreCase).toBoolean(exec))
+ postfix[index++] = 'i';
+ if (thisObject->get(exec, exec->propertyNames().multiline).toBoolean(exec))
+ postfix[index] = 'm';
+ UString source = thisObject->get(exec, exec->propertyNames().source).toString(exec);
+ // If source is empty, use "/(?:)/" to avoid colliding with comment syntax
+ return JSValue::encode(jsMakeNontrivialString(exec, "/", source.length() ? source : UString("(?:)"), postfix));
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/RegExpPrototype.h b/Source/JavaScriptCore/runtime/RegExpPrototype.h
new file mode 100644
index 000000000..6702592fd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/RegExpPrototype.h
@@ -0,0 +1,58 @@
+/*
+ * 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 "RegExpObject.h"
+#include "JSObject.h"
+
+namespace JSC {
+
+ class RegExpPrototype : public RegExpObject {
+ public:
+ typedef RegExpObject Base;
+
+ static RegExpPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure, RegExp* regExp)
+ {
+ RegExpPrototype* prototype = new (NotNull, allocateCell<RegExpPrototype>(*exec->heap())) RegExpPrototype(globalObject, structure, regExp);
+ prototype->finishCreation(globalObject);
+ return prototype;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ RegExpPrototype(JSGlobalObject*, Structure*, RegExp*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | RegExpObject::StructureFlags;
+
+ private:
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ };
+
+} // namespace JSC
+
+#endif // RegExpPrototype_h
diff --git a/Source/JavaScriptCore/runtime/SamplingCounter.cpp b/Source/JavaScriptCore/runtime/SamplingCounter.cpp
new file mode 100644
index 000000000..e5fb25a93
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SamplingCounter.cpp
@@ -0,0 +1,52 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 "SamplingCounter.h"
+
+namespace JSC {
+
+void AbstractSamplingCounter::dump()
+{
+#if ENABLE(SAMPLING_COUNTERS)
+ if (s_abstractSamplingCounterChain != &s_abstractSamplingCounterChainEnd) {
+ printf("\nSampling Counter Values:\n");
+ for (AbstractSamplingCounter* currCounter = s_abstractSamplingCounterChain; (currCounter != &s_abstractSamplingCounterChainEnd); currCounter = currCounter->m_next)
+ printf("\t%s\t: %lld\n", currCounter->m_name, currCounter->m_counter);
+ printf("\n\n");
+ }
+ s_completed = true;
+#endif
+}
+
+AbstractSamplingCounter AbstractSamplingCounter::s_abstractSamplingCounterChainEnd;
+AbstractSamplingCounter* AbstractSamplingCounter::s_abstractSamplingCounterChain = &s_abstractSamplingCounterChainEnd;
+bool AbstractSamplingCounter::s_completed = false;
+
+} // namespace JSC
+
diff --git a/Source/JavaScriptCore/runtime/SamplingCounter.h b/Source/JavaScriptCore/runtime/SamplingCounter.h
new file mode 100644
index 000000000..664b0280e
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SamplingCounter.h
@@ -0,0 +1,178 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 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 SamplingCounter_h
+#define SamplingCounter_h
+
+#include <stdint.h>
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+// AbstractSamplingCounter:
+//
+// Implements a named set of counters, printed on exit if ENABLE(SAMPLING_COUNTERS).
+// See subclasses below, SamplingCounter, GlobalSamplingCounter and DeletableSamplingCounter.
+class AbstractSamplingCounter {
+ friend class DeletableSamplingCounter;
+public:
+ void count(uint32_t count = 1)
+ {
+ m_counter += count;
+ }
+
+ static void dump();
+
+ int64_t* addressOfCounter() { return &m_counter; }
+
+protected:
+ // Effectively the contructor, however called lazily in the case of GlobalSamplingCounter.
+ void init(const char* name)
+ {
+ m_counter = 0;
+ m_name = name;
+
+ // Set m_next to point to the head of the chain, and inform whatever is
+ // currently at the head that this node will now hold the pointer to it.
+ m_next = s_abstractSamplingCounterChain;
+ s_abstractSamplingCounterChain->m_referer = &m_next;
+ // Add this node to the head of the list.
+ s_abstractSamplingCounterChain = this;
+ m_referer = &s_abstractSamplingCounterChain;
+ }
+
+ int64_t m_counter;
+ const char* m_name;
+ AbstractSamplingCounter* m_next;
+ // This is a pointer to the pointer to this node in the chain; used to
+ // allow fast linked list deletion.
+ AbstractSamplingCounter** m_referer;
+ // Null object used to detect end of static chain.
+ static AbstractSamplingCounter s_abstractSamplingCounterChainEnd;
+ static AbstractSamplingCounter* s_abstractSamplingCounterChain;
+ static bool s_completed;
+};
+
+#if ENABLE(SAMPLING_COUNTERS)
+// SamplingCounter:
+//
+// This class is suitable and (hopefully!) convenient for cases where a counter is
+// required within the scope of a single function. It can be instantiated as a
+// static variable since it contains a constructor but not a destructor (static
+// variables in WebKit cannot have destructors).
+//
+// For example:
+//
+// void someFunction()
+// {
+// static SamplingCounter countMe("This is my counter. There are many like it, but this one is mine.");
+// countMe.count();
+// // ...
+// }
+//
+class SamplingCounter : public AbstractSamplingCounter {
+public:
+ SamplingCounter(const char* name) { init(name); }
+};
+
+// GlobalSamplingCounter:
+//
+// This class is suitable for use where a counter is to be declared globally,
+// since it contains neither a constructor nor destructor. Instead, ensure
+// that 'name()' is called to provide the counter with a name (and also to
+// allow it to be printed out on exit).
+//
+// GlobalSamplingCounter globalCounter;
+//
+// void firstFunction()
+// {
+// // Put this within a function that is definitely called!
+// // (Or alternatively alongside all calls to 'count()').
+// globalCounter.name("I Name You Destroyer.");
+// globalCounter.count();
+// // ...
+// }
+//
+// void secondFunction()
+// {
+// globalCounter.count();
+// // ...
+// }
+//
+class GlobalSamplingCounter : public AbstractSamplingCounter {
+public:
+ void name(const char* name)
+ {
+ // Global objects should be mapped in zero filled memory, so this should
+ // be a safe (albeit not necessarily threadsafe) check for 'first call'.
+ if (!m_next)
+ init(name);
+ }
+};
+
+// DeletableSamplingCounter:
+//
+// The above classes (SamplingCounter, GlobalSamplingCounter), are intended for
+// use within a global or static scope, and as such cannot have a destructor.
+// This means there is no convenient way for them to remove themselves from the
+// static list of counters, and should an instance of either class be freed
+// before 'dump()' has walked over the list it will potentially walk over an
+// invalid pointer.
+//
+// This class is intended for use where the counter may possibly be deleted before
+// the program exits. Should this occur, the counter will print it's value to
+// stderr, and remove itself from the static list. Example:
+//
+// DeletableSamplingCounter* counter = new DeletableSamplingCounter("The Counter With No Name");
+// counter->count();
+// delete counter;
+//
+class DeletableSamplingCounter : public AbstractSamplingCounter {
+public:
+ DeletableSamplingCounter(const char* name) { init(name); }
+
+ ~DeletableSamplingCounter()
+ {
+ if (!s_completed)
+ fprintf(stderr, "DeletableSamplingCounter \"%s\" deleted early (with count %lld)\n", m_name, m_counter);
+ // Our m_referer pointer should know where the pointer to this node is,
+ // and m_next should know that this node is the previous node in the list.
+ ASSERT(*m_referer == this);
+ ASSERT(m_next->m_referer == &m_next);
+ // Remove this node from the list, and inform m_next that we have done so.
+ m_next->m_referer = m_referer;
+ *m_referer = m_next;
+ }
+};
+#endif
+
+} // namespace JSC
+
+#endif // SamplingCounter_h
+
+
diff --git a/Source/JavaScriptCore/runtime/ScopeChain.cpp b/Source/JavaScriptCore/runtime/ScopeChain.cpp
new file mode 100644
index 000000000..099f7fde6
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopeChain.cpp
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 Apple Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "ScopeChain.h"
+
+#include "JSActivation.h"
+#include "JSGlobalObject.h"
+#include "JSObject.h"
+#include "PropertyNameArray.h"
+#include <stdio.h>
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(ScopeChainNode);
+
+#ifndef NDEBUG
+
+void ScopeChainNode::print()
+{
+ ScopeChainIterator scopeEnd = end();
+ for (ScopeChainIterator scopeIter = begin(); scopeIter != scopeEnd; ++scopeIter) {
+ JSObject* o = scopeIter->get();
+ PropertyNameArray propertyNames(globalObject->globalExec());
+ o->methodTable()->getPropertyNames(o, globalObject->globalExec(), propertyNames, ExcludeDontEnumProperties);
+ 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.ustring().utf8().data());
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
+#endif
+
+const ClassInfo ScopeChainNode::s_info = { "ScopeChainNode", 0, 0, 0, CREATE_METHOD_TABLE(ScopeChainNode) };
+
+int ScopeChainNode::localDepth()
+{
+ int scopeDepth = 0;
+ ScopeChainIterator iter = this->begin();
+ ScopeChainIterator end = this->end();
+ while (!(*iter)->inherits(&JSActivation::s_info)) {
+ ++iter;
+ if (iter == end)
+ break;
+ ++scopeDepth;
+ }
+ return scopeDepth;
+}
+
+void ScopeChainNode::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ ScopeChainNode* thisObject = jsCast<ScopeChainNode*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ COMPILE_ASSERT(StructureFlags & OverridesVisitChildren, OverridesVisitChildrenWithoutSettingFlag);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ if (thisObject->next)
+ visitor.append(&thisObject->next);
+ visitor.append(&thisObject->object);
+ visitor.append(&thisObject->globalObject);
+ visitor.append(&thisObject->globalThis);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/ScopeChain.h b/Source/JavaScriptCore/runtime/ScopeChain.h
new file mode 100644
index 000000000..6e358d779
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopeChain.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2003, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ScopeChain_h
+#define ScopeChain_h
+
+#include "JSCell.h"
+#include "Structure.h"
+#include <wtf/FastAllocBase.h>
+
+namespace JSC {
+
+ class JSGlobalData;
+ class JSGlobalObject;
+ class JSObject;
+ class ScopeChainIterator;
+ class SlotVisitor;
+
+ class ScopeChainNode : public JSCell {
+ private:
+ ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
+ : JSCell(*globalData, globalData->scopeChainNodeStructure.get())
+ , globalData(globalData)
+ , next(*globalData, this, next, WriteBarrier<ScopeChainNode>::MayBeNull)
+ , object(*globalData, this, object)
+ , globalObject(*globalData, this, globalObject)
+ , globalThis(*globalData, this, globalThis)
+ {
+ }
+
+ protected:
+ void finishCreation(JSGlobalData* globalData, JSGlobalObject* globalObject)
+ {
+ Base::finishCreation(*globalData);
+ ASSERT_UNUSED(globalObject, globalObject);
+ }
+
+ public:
+ typedef JSCell Base;
+
+ static ScopeChainNode* create(ExecState* exec, ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
+ {
+ ScopeChainNode* node = new (NotNull, allocateCell<ScopeChainNode>(*exec->heap())) ScopeChainNode(next, object, globalData, globalObject, globalThis);
+ node->finishCreation(globalData, globalObject);
+ return node;
+ }
+ static ScopeChainNode* create(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis)
+ {
+ ScopeChainNode* node = new (NotNull, allocateCell<ScopeChainNode>(globalData->heap)) ScopeChainNode(next, object, globalData, globalObject, globalThis);
+ node->finishCreation(globalData, globalObject);
+ return node;
+ }
+
+ JSGlobalData* globalData;
+ WriteBarrier<ScopeChainNode> next;
+ WriteBarrier<JSObject> object;
+ WriteBarrier<JSGlobalObject> globalObject;
+ WriteBarrier<JSObject> globalThis;
+
+ ScopeChainNode* push(JSObject*);
+ ScopeChainNode* pop();
+
+ ScopeChainIterator begin();
+ ScopeChainIterator end();
+
+ int localDepth();
+
+#ifndef NDEBUG
+ void print();
+#endif
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue proto) { return Structure::create(globalData, globalObject, proto, TypeInfo(CompoundType, StructureFlags), &s_info); }
+ static void visitChildren(JSCell*, SlotVisitor&);
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ private:
+ static const unsigned StructureFlags = OverridesVisitChildren;
+ };
+
+ inline ScopeChainNode* ScopeChainNode::push(JSObject* o)
+ {
+ ASSERT(o);
+ return ScopeChainNode::create(this, o, globalData, globalObject.get(), globalThis.get());
+ }
+
+ inline ScopeChainNode* ScopeChainNode::pop()
+ {
+ ASSERT(next);
+ return next.get();
+ }
+
+ class ScopeChainIterator {
+ public:
+ ScopeChainIterator(ScopeChainNode* node)
+ : m_node(node)
+ {
+ }
+
+ WriteBarrier<JSObject> const & operator*() const { return m_node->object; }
+ WriteBarrier<JSObject> const * operator->() const { return &(operator*()); }
+
+ ScopeChainIterator& operator++() { m_node = m_node->next.get(); 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:
+ ScopeChainNode* m_node;
+ };
+
+ inline ScopeChainIterator ScopeChainNode::begin()
+ {
+ return ScopeChainIterator(this);
+ }
+
+ inline ScopeChainIterator ScopeChainNode::end()
+ {
+ return ScopeChainIterator(0);
+ }
+
+ ALWAYS_INLINE JSGlobalData& ExecState::globalData() const
+ {
+ ASSERT(scopeChain()->globalData);
+ return *scopeChain()->globalData;
+ }
+
+ ALWAYS_INLINE JSGlobalObject* ExecState::lexicalGlobalObject() const
+ {
+ return scopeChain()->globalObject.get();
+ }
+
+ ALWAYS_INLINE JSObject* ExecState::globalThisValue() const
+ {
+ return scopeChain()->globalThis.get();
+ }
+
+ ALWAYS_INLINE ScopeChainNode* Register::scopeChain() const
+ {
+ return static_cast<ScopeChainNode*>(jsValue().asCell());
+ }
+
+ ALWAYS_INLINE Register& Register::operator=(ScopeChainNode* scopeChain)
+ {
+ *this = JSValue(scopeChain);
+ return *this;
+ }
+
+} // namespace JSC
+
+#endif // ScopeChain_h
diff --git a/Source/JavaScriptCore/runtime/ScopeChainMark.h b/Source/JavaScriptCore/runtime/ScopeChainMark.h
new file mode 100644
index 000000000..35701f11d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/ScopeChainMark.h
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2003, 2006, 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ScopeChainMark_h
+#define ScopeChainMark_h
+
+#include "ScopeChain.h"
+
+namespace JSC {
+
+} // namespace JSC
+
+#endif // ScopeChainMark_h
diff --git a/Source/JavaScriptCore/runtime/SmallStrings.cpp b/Source/JavaScriptCore/runtime/SmallStrings.cpp
new file mode 100644
index 000000000..caf201c3d
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SmallStrings.cpp
@@ -0,0 +1,127 @@
+/*
+ * Copyright (C) 2008, 2010 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED 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 "HeapRootVisitor.h"
+#include "JSGlobalObject.h"
+#include "JSString.h"
+#include <wtf/Noncopyable.h>
+#include <wtf/PassOwnPtr.h>
+
+namespace JSC {
+
+static inline void finalize(JSString*& string)
+{
+ if (!string || Heap::isMarked(string))
+ return;
+ string = 0;
+}
+
+class SmallStringsStorage {
+ WTF_MAKE_NONCOPYABLE(SmallStringsStorage); WTF_MAKE_FAST_ALLOCATED;
+public:
+ SmallStringsStorage();
+
+ StringImpl* rep(unsigned char character)
+ {
+ return m_reps[character].get();
+ }
+
+private:
+ static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1;
+
+ RefPtr<StringImpl> m_reps[singleCharacterStringCount];
+};
+
+SmallStringsStorage::SmallStringsStorage()
+{
+ LChar* characterBuffer = 0;
+ RefPtr<StringImpl> baseString = StringImpl::createUninitialized(singleCharacterStringCount, characterBuffer);
+ for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
+ characterBuffer[i] = i;
+ m_reps[i] = StringImpl::create(baseString, i, 1);
+ }
+}
+
+SmallStrings::SmallStrings()
+{
+ COMPILE_ASSERT(singleCharacterStringCount == sizeof(m_singleCharacterStrings) / sizeof(m_singleCharacterStrings[0]), IsNumCharactersConstInSyncWithClassUsage);
+ clear();
+}
+
+SmallStrings::~SmallStrings()
+{
+}
+
+void SmallStrings::finalizeSmallStrings()
+{
+ finalize(m_emptyString);
+ for (unsigned i = 0; i < singleCharacterStringCount; ++i)
+ finalize(m_singleCharacterStrings[i]);
+}
+
+void SmallStrings::clear()
+{
+ m_emptyString = 0;
+ for (unsigned i = 0; i < singleCharacterStringCount; ++i)
+ m_singleCharacterStrings[i] = 0;
+}
+
+unsigned SmallStrings::count() const
+{
+ unsigned count = 0;
+ if (m_emptyString)
+ ++count;
+ for (unsigned i = 0; i < singleCharacterStringCount; ++i) {
+ if (m_singleCharacterStrings[i])
+ ++count;
+ }
+ return count;
+}
+
+void SmallStrings::createEmptyString(JSGlobalData* globalData)
+{
+ ASSERT(!m_emptyString);
+ m_emptyString = JSString::createHasOtherOwner(*globalData, StringImpl::empty());
+}
+
+void SmallStrings::createSingleCharacterString(JSGlobalData* globalData, unsigned char character)
+{
+ if (!m_storage)
+ m_storage = adoptPtr(new SmallStringsStorage);
+ ASSERT(!m_singleCharacterStrings[character]);
+ m_singleCharacterStrings[character] = JSString::createHasOtherOwner(*globalData, PassRefPtr<StringImpl>(m_storage->rep(character)));
+}
+
+StringImpl* SmallStrings::singleCharacterStringRep(unsigned char character)
+{
+ if (!m_storage)
+ m_storage = adoptPtr(new SmallStringsStorage);
+ return m_storage->rep(character);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/SmallStrings.h b/Source/JavaScriptCore/runtime/SmallStrings.h
new file mode 100644
index 000000000..9c6ed9a32
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SmallStrings.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SmallStrings_h
+#define SmallStrings_h
+
+#include "UString.h"
+#include <wtf/FixedArray.h>
+#include <wtf/OwnPtr.h>
+
+namespace JSC {
+
+ class HeapRootVisitor;
+ class JSGlobalData;
+ class JSString;
+ class SmallStringsStorage;
+ class SlotVisitor;
+
+ static const unsigned maxSingleCharacterString = 0xFF;
+
+ class SmallStrings {
+ WTF_MAKE_NONCOPYABLE(SmallStrings);
+ 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];
+ }
+
+ StringImpl* singleCharacterStringRep(unsigned char character);
+
+ void finalizeSmallStrings();
+ void clear();
+
+ unsigned count() const;
+
+ JSString** singleCharacterStrings() { return &m_singleCharacterStrings[0]; }
+
+ private:
+ static const unsigned singleCharacterStringCount = maxSingleCharacterString + 1;
+
+ void createEmptyString(JSGlobalData*);
+ void createSingleCharacterString(JSGlobalData*, unsigned char);
+
+ JSString* m_emptyString;
+ JSString* m_singleCharacterStrings[singleCharacterStringCount];
+ OwnPtr<SmallStringsStorage> m_storage;
+ };
+
+} // namespace JSC
+
+#endif // SmallStrings_h
diff --git a/Source/JavaScriptCore/runtime/StorageBarrier.h b/Source/JavaScriptCore/runtime/StorageBarrier.h
new file mode 100644
index 000000000..2a0c842ba
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StorageBarrier.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StorageBarrier_h
+#define StorageBarrier_h
+
+#include "JSGlobalData.h"
+#include "WriteBarrier.h"
+
+namespace JSC {
+
+typedef WriteBarrierBase<Unknown>* PropertyStorage;
+typedef const WriteBarrierBase<Unknown>* ConstPropertyStorage;
+
+class StorageBarrier {
+public:
+ enum UncheckedTag { Unchecked };
+ StorageBarrier(JSGlobalData& globalData, JSCell* owner, PropertyStorage storage)
+ {
+ set(globalData, owner, storage);
+ }
+
+ StorageBarrier(PropertyStorage storage, UncheckedTag)
+ {
+ set(storage, Unchecked);
+ }
+
+ void set(JSGlobalData&, JSCell*, PropertyStorage newStorage)
+ {
+ m_storage = newStorage;
+ }
+
+ void set(PropertyStorage newStorage, UncheckedTag)
+ {
+ m_storage = newStorage;
+ }
+
+ WriteBarrierBase<Unknown>* operator->() const { return m_storage; }
+ WriteBarrierBase<Unknown>* operator->() { return m_storage; }
+ WriteBarrierBase<Unknown> operator*() const { return *m_storage; }
+ WriteBarrierBase<Unknown> operator*() { return *m_storage; }
+ const WriteBarrierBase<Unknown>& operator[](size_t i) const { return m_storage[i]; }
+ WriteBarrierBase<Unknown>& operator[](size_t i) { return m_storage[i]; }
+
+ ConstPropertyStorage get() const { return m_storage; }
+ PropertyStorage get() { return m_storage; }
+
+private:
+ PropertyStorage m_storage;
+};
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp
new file mode 100644
index 000000000..fbd9d5fbd
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StrictEvalActivation.h"
+
+namespace JSC {
+
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(StrictEvalActivation);
+
+const ClassInfo StrictEvalActivation::s_info = { "Object", &Base::s_info, 0, 0, CREATE_METHOD_TABLE(StrictEvalActivation) };
+
+StrictEvalActivation::StrictEvalActivation(ExecState* exec)
+ : JSNonFinalObject(exec->globalData(), exec->globalData().strictEvalActivationStructure.get())
+{
+}
+
+bool StrictEvalActivation::deleteProperty(JSCell*, ExecState*, const Identifier&)
+{
+ return false;
+}
+
+JSObject* StrictEvalActivation::toThisObject(JSCell*, ExecState* exec)
+{
+ return exec->globalThisValue();
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/StrictEvalActivation.h b/Source/JavaScriptCore/runtime/StrictEvalActivation.h
new file mode 100644
index 000000000..a7b6d3e96
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StrictEvalActivation.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StrictEvalActivation_h
+#define StrictEvalActivation_h
+
+#include "JSObject.h"
+
+namespace JSC {
+
+class StrictEvalActivation : public JSNonFinalObject {
+public:
+ typedef JSNonFinalObject Base;
+
+ static StrictEvalActivation* create(ExecState* exec)
+ {
+ StrictEvalActivation* activation = new (NotNull, allocateCell<StrictEvalActivation>(*exec->heap())) StrictEvalActivation(exec);
+ activation->finishCreation(exec->globalData());
+ return activation;
+ }
+
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier&);
+ static JSObject* toThisObject(JSCell*, ExecState*);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+protected:
+ static const unsigned StructureFlags = IsEnvironmentRecord | JSNonFinalObject::StructureFlags;
+
+private:
+ StrictEvalActivation(ExecState*);
+};
+
+} // namespace JSC
+
+#endif // StrictEvalActivation_h
diff --git a/Source/JavaScriptCore/runtime/StringConstructor.cpp b/Source/JavaScriptCore/runtime/StringConstructor.cpp
new file mode 100644
index 000000000..d2f75a060
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringConstructor.cpp
@@ -0,0 +1,123 @@
+/*
+ * 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 "Executable.h"
+#include "JITCode.h"
+#include "JSFunction.h"
+#include "JSGlobalObject.h"
+#include "StringPrototype.h"
+
+namespace JSC {
+
+static EncodedJSValue JSC_HOST_CALL stringFromCharCode(ExecState*);
+
+}
+
+#include "StringConstructor.lut.h"
+
+namespace JSC {
+
+const ClassInfo StringConstructor::s_info = { "Function", &InternalFunction::s_info, 0, ExecState::stringConstructorTable, CREATE_METHOD_TABLE(StringConstructor) };
+
+/* Source for StringConstructor.lut.h
+@begin stringConstructorTable
+ fromCharCode stringFromCharCode DontEnum|Function 1
+@end
+*/
+
+ASSERT_CLASS_FITS_IN_CELL(StringConstructor);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringConstructor);
+
+StringConstructor::StringConstructor(JSGlobalObject* globalObject, Structure* structure)
+ : InternalFunction(globalObject, structure)
+{
+}
+
+void StringConstructor::finishCreation(ExecState* exec, StringPrototype* stringPrototype)
+{
+ Base::finishCreation(exec->globalData(), Identifier(exec, stringPrototype->classInfo()->className));
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().prototype, stringPrototype, ReadOnly | DontEnum | DontDelete);
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(1), ReadOnly | DontEnum | DontDelete);
+}
+
+bool StringConstructor::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<InternalFunction>(exec, ExecState::stringConstructorTable(exec), jsCast<StringConstructor*>(cell), propertyName, slot);
+}
+
+bool StringConstructor::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<InternalFunction>(exec, ExecState::stringConstructorTable(exec), jsCast<StringConstructor*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Functions --------------------------------
+
+static NEVER_INLINE JSValue stringFromCharCodeSlowCase(ExecState* exec)
+{
+ unsigned length = exec->argumentCount();
+ UChar* buf;
+ PassRefPtr<StringImpl> impl = StringImpl::createUninitialized(length, buf);
+ for (unsigned i = 0; i < length; ++i)
+ buf[i] = static_cast<UChar>(exec->argument(i).toUInt32(exec));
+ return jsString(exec, impl);
+}
+
+static EncodedJSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec)
+{
+ if (LIKELY(exec->argumentCount() == 1))
+ return JSValue::encode(jsSingleCharacterString(exec, exec->argument(0).toUInt32(exec)));
+ return JSValue::encode(stringFromCharCodeSlowCase(exec));
+}
+
+static EncodedJSValue JSC_HOST_CALL constructWithStringConstructor(ExecState* exec)
+{
+ JSGlobalObject* globalObject = asInternalFunction(exec->callee())->globalObject();
+ if (!exec->argumentCount())
+ return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure()));
+
+ JSString* string = exec->argument(0).isString()
+ ? asString(exec->argument(0))
+ : jsString(exec, exec->argument(0).toString(exec));
+ return JSValue::encode(StringObject::create(exec, globalObject->stringObjectStructure(), string));
+}
+
+ConstructType StringConstructor::getConstructData(JSCell*, ConstructData& constructData)
+{
+ constructData.native.function = constructWithStringConstructor;
+ return ConstructTypeHost;
+}
+
+static EncodedJSValue JSC_HOST_CALL callStringConstructor(ExecState* exec)
+{
+ if (!exec->argumentCount())
+ return JSValue::encode(jsEmptyString(exec));
+ return JSValue::encode(jsString(exec, exec->argument(0).toString(exec)));
+}
+
+CallType StringConstructor::getCallData(JSCell*, CallData& callData)
+{
+ callData.native.function = callStringConstructor;
+ return CallTypeHost;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StringConstructor.h b/Source/JavaScriptCore/runtime/StringConstructor.h
new file mode 100644
index 000000000..6f553cdbb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringConstructor.h
@@ -0,0 +1,63 @@
+/*
+ * 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:
+ typedef InternalFunction Base;
+
+ static StringConstructor* create(ExecState* exec, JSGlobalObject* globalObject , Structure* structure, StringPrototype* stringPrototype)
+ {
+ StringConstructor* constructor = new (NotNull, allocateCell<StringConstructor>(*exec->heap())) StringConstructor(globalObject, structure);
+ constructor->finishCreation(exec, stringPrototype);
+ return constructor;
+ }
+
+ static const ClassInfo s_info;
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | InternalFunction::StructureFlags;
+
+ private:
+ StringConstructor(JSGlobalObject*, Structure*);
+ void finishCreation(ExecState*, StringPrototype*);
+ static ConstructType getConstructData(JSCell*, ConstructData&);
+ static CallType getCallData(JSCell*, CallData&);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier&, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+ };
+
+} // namespace JSC
+
+#endif // StringConstructor_h
diff --git a/Source/JavaScriptCore/runtime/StringObject.cpp b/Source/JavaScriptCore/runtime/StringObject.cpp
new file mode 100644
index 000000000..4a24698fb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringObject.cpp
@@ -0,0 +1,99 @@
+/*
+ * 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);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringObject);
+
+const ClassInfo StringObject::s_info = { "String", &JSWrapperObject::s_info, 0, 0, CREATE_METHOD_TABLE(StringObject) };
+
+StringObject::StringObject(JSGlobalData& globalData, Structure* structure)
+ : JSWrapperObject(globalData, structure)
+{
+}
+
+void StringObject::finishCreation(JSGlobalData& globalData, JSString* string)
+{
+ Base::finishCreation(globalData);
+ ASSERT(inherits(&s_info));
+ setInternalValue(globalData, string);
+}
+
+bool StringObject::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ StringObject* thisObject = jsCast<StringObject*>(cell);
+ if (thisObject->internalValue()->getStringPropertySlot(exec, propertyName, slot))
+ return true;
+ return JSObject::getOwnPropertySlot(thisObject, exec, propertyName, slot);
+}
+
+bool StringObject::getOwnPropertySlotByIndex(JSCell* cell, ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ StringObject* thisObject = jsCast<StringObject*>(cell);
+ if (thisObject->internalValue()->getStringPropertySlot(exec, propertyName, slot))
+ return true;
+ return JSObject::getOwnPropertySlot(thisObject, exec, Identifier::from(exec, propertyName), slot);
+}
+
+bool StringObject::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ StringObject* thisObject = jsCast<StringObject*>(object);
+ if (thisObject->internalValue()->getStringPropertyDescriptor(exec, propertyName, descriptor))
+ return true;
+ return JSObject::getOwnPropertyDescriptor(thisObject, exec, propertyName, descriptor);
+}
+
+void StringObject::put(JSCell* cell, ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot)
+{
+ if (propertyName == exec->propertyNames().length)
+ return;
+ JSObject::put(cell, exec, propertyName, value, slot);
+}
+
+bool StringObject::deleteProperty(JSCell* cell, ExecState* exec, const Identifier& propertyName)
+{
+ StringObject* thisObject = jsCast<StringObject*>(cell);
+ if (propertyName == exec->propertyNames().length)
+ return false;
+ bool isStrictUInt32;
+ unsigned i = propertyName.toUInt32(isStrictUInt32);
+ if (isStrictUInt32 && thisObject->internalValue()->canGetIndex(i))
+ return false;
+ return JSObject::deleteProperty(thisObject, exec, propertyName);
+}
+
+void StringObject::getOwnPropertyNames(JSObject* object, ExecState* exec, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ StringObject* thisObject = jsCast<StringObject*>(object);
+ int size = thisObject->internalValue()->length();
+ for (int i = 0; i < size; ++i)
+ propertyNames.add(Identifier(exec, UString::number(i)));
+ if (mode == IncludeDontEnumProperties)
+ propertyNames.add(exec->propertyNames().length);
+ return JSObject::getOwnPropertyNames(thisObject, exec, propertyNames, mode);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StringObject.h b/Source/JavaScriptCore/runtime/StringObject.h
new file mode 100644
index 000000000..528668691
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringObject.h
@@ -0,0 +1,82 @@
+/*
+ * 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:
+ typedef JSWrapperObject Base;
+
+ static StringObject* create(ExecState* exec, Structure* structure)
+ {
+ JSString* string = jsEmptyString(exec);
+ StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->globalData(), structure);
+ object->finishCreation(exec->globalData(), string);
+ return object;
+ }
+ static StringObject* create(ExecState* exec, Structure* structure, JSString* string)
+ {
+ StringObject* object = new (NotNull, allocateCell<StringObject>(*exec->heap())) StringObject(exec->globalData(), structure);
+ object->finishCreation(exec->globalData(), string);
+ return object;
+ }
+ static StringObject* create(ExecState*, JSGlobalObject*, JSString*);
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertySlotByIndex(JSCell*, ExecState*, unsigned propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static void put(JSCell*, ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&);
+
+ static bool deleteProperty(JSCell*, ExecState*, const Identifier& propertyName);
+ static void getOwnPropertyNames(JSObject*, ExecState*, PropertyNameArray&, EnumerationMode);
+
+ static const JS_EXPORTDATA ClassInfo s_info;
+
+ JSString* internalValue() const { return asString(JSWrapperObject::internalValue());}
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ protected:
+ void finishCreation(JSGlobalData&, JSString*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSWrapperObject::StructureFlags;
+ StringObject(JSGlobalData&, Structure*);
+ };
+
+ StringObject* asStringObject(JSValue);
+
+ inline StringObject* asStringObject(JSValue value)
+ {
+ ASSERT(asObject(value)->inherits(&StringObject::s_info));
+ return static_cast<StringObject*>(asObject(value));
+ }
+
+} // namespace JSC
+
+#endif // StringObject_h
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.cpp b/Source/JavaScriptCore/runtime/StringPrototype.cpp
new file mode 100644
index 000000000..740916a69
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringPrototype.cpp
@@ -0,0 +1,1490 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Torch Mobile, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "StringPrototype.h"
+
+#include "CachedCall.h"
+#include "Error.h"
+#include "Executable.h"
+#include "JSGlobalObjectFunctions.h"
+#include "JSArray.h"
+#include "JSFunction.h"
+#include "JSStringBuilder.h"
+#include "Lookup.h"
+#include "ObjectPrototype.h"
+#include "Operations.h"
+#include "PropertyNameArray.h"
+#include "RegExpCache.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);
+ASSERT_HAS_TRIVIAL_DESTRUCTOR(StringPrototype);
+
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*);
+static EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*);
+
+}
+
+#include "StringPrototype.lut.h"
+
+namespace JSC {
+
+const ClassInfo StringPrototype::s_info = { "String", &StringObject::s_info, 0, ExecState::stringTable, CREATE_METHOD_TABLE(StringPrototype) };
+
+/* Source for StringPrototype.lut.h
+@begin stringTable 26
+ toString stringProtoFuncToString DontEnum|Function 0
+ valueOf stringProtoFuncToString DontEnum|Function 0
+ charAt stringProtoFuncCharAt DontEnum|Function 1
+ charCodeAt stringProtoFuncCharCodeAt DontEnum|Function 1
+ concat stringProtoFuncConcat DontEnum|Function 1
+ indexOf stringProtoFuncIndexOf DontEnum|Function 1
+ lastIndexOf stringProtoFuncLastIndexOf DontEnum|Function 1
+ match stringProtoFuncMatch DontEnum|Function 1
+ replace stringProtoFuncReplace DontEnum|Function 2
+ search stringProtoFuncSearch DontEnum|Function 1
+ slice stringProtoFuncSlice DontEnum|Function 2
+ split stringProtoFuncSplit DontEnum|Function 2
+ substr stringProtoFuncSubstr DontEnum|Function 2
+ substring stringProtoFuncSubstring DontEnum|Function 2
+ toLowerCase stringProtoFuncToLowerCase DontEnum|Function 0
+ toUpperCase stringProtoFuncToUpperCase DontEnum|Function 0
+ localeCompare stringProtoFuncLocaleCompare DontEnum|Function 1
+
+ # toLocaleLowerCase and toLocaleUpperCase are currently identical to toLowerCase and toUpperCase
+ toLocaleLowerCase stringProtoFuncToLowerCase DontEnum|Function 0
+ toLocaleUpperCase stringProtoFuncToUpperCase DontEnum|Function 0
+
+ big stringProtoFuncBig DontEnum|Function 0
+ small stringProtoFuncSmall DontEnum|Function 0
+ blink stringProtoFuncBlink DontEnum|Function 0
+ bold stringProtoFuncBold DontEnum|Function 0
+ fixed stringProtoFuncFixed DontEnum|Function 0
+ italics stringProtoFuncItalics DontEnum|Function 0
+ strike stringProtoFuncStrike DontEnum|Function 0
+ sub stringProtoFuncSub DontEnum|Function 0
+ sup stringProtoFuncSup DontEnum|Function 0
+ fontcolor stringProtoFuncFontcolor DontEnum|Function 1
+ fontsize stringProtoFuncFontsize DontEnum|Function 1
+ anchor stringProtoFuncAnchor DontEnum|Function 1
+ link stringProtoFuncLink DontEnum|Function 1
+ trim stringProtoFuncTrim DontEnum|Function 0
+ trimLeft stringProtoFuncTrimLeft DontEnum|Function 0
+ trimRight stringProtoFuncTrimRight DontEnum|Function 0
+@end
+*/
+
+// ECMA 15.5.4
+StringPrototype::StringPrototype(ExecState* exec, Structure* structure)
+ : StringObject(exec->globalData(), structure)
+{
+}
+
+void StringPrototype::finishCreation(ExecState* exec, JSGlobalObject*, JSString* nameAndMessage)
+{
+ Base::finishCreation(exec->globalData(), nameAndMessage);
+ ASSERT(inherits(&s_info));
+
+ // The constructor will be added later, after StringConstructor has been built
+ putDirectWithoutTransition(exec->globalData(), exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
+}
+
+bool StringPrototype::getOwnPropertySlot(JSCell* cell, ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<StringObject>(exec, ExecState::stringTable(exec), jsCast<StringPrototype*>(cell), propertyName, slot);
+}
+
+bool StringPrototype::getOwnPropertyDescriptor(JSObject* object, ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor)
+{
+ return getStaticFunctionDescriptor<StringObject>(exec, ExecState::stringTable(exec), jsCast<StringPrototype*>(object), propertyName, descriptor);
+}
+
+// ------------------------------ Functions --------------------------
+
+// Helper for producing a JSString for 'string', where 'string' was been produced by
+// calling ToString on 'originalValue'. In cases where 'originalValue' already was a
+// string primitive we can just use this, otherwise we need to allocate a new JSString.
+static inline JSString* jsStringWithReuse(ExecState* exec, JSValue originalValue, const UString& string)
+{
+ if (originalValue.isString()) {
+ ASSERT(asString(originalValue)->value(exec) == string);
+ return asString(originalValue);
+ }
+ return jsString(exec, string);
+}
+
+static NEVER_INLINE UString substituteBackreferencesSlow(const UString& replacement, const UString& source, const int* ovector, RegExp* reg, size_t i)
+{
+ Vector<UChar> substitutedReplacement;
+ int offset = 0;
+ do {
+ if (i + 1 == replacement.length())
+ break;
+
+ UChar ref = replacement[i + 1];
+ if (ref == '$') {
+ // "$$" -> "$"
+ ++i;
+ substitutedReplacement.append(replacement.characters() + offset, i - offset);
+ offset = i + 1;
+ continue;
+ }
+
+ int backrefStart;
+ int backrefLength;
+ int advance = 0;
+ if (ref == '&') {
+ backrefStart = ovector[0];
+ backrefLength = ovector[1] - backrefStart;
+ } else if (ref == '`') {
+ backrefStart = 0;
+ backrefLength = ovector[0];
+ } else if (ref == '\'') {
+ backrefStart = ovector[1];
+ backrefLength = source.length() - backrefStart;
+ } else if (reg && ref >= '0' && ref <= '9') {
+ // 1- and 2-digit back references are allowed
+ unsigned backrefIndex = ref - '0';
+ if (backrefIndex > reg->numSubpatterns())
+ continue;
+ if (replacement.length() > i + 2) {
+ ref = replacement[i + 2];
+ if (ref >= '0' && ref <= '9') {
+ backrefIndex = 10 * backrefIndex + ref - '0';
+ if (backrefIndex > reg->numSubpatterns())
+ backrefIndex = backrefIndex / 10; // Fall back to the 1-digit reference
+ else
+ advance = 1;
+ }
+ }
+ if (!backrefIndex)
+ continue;
+ backrefStart = ovector[2 * backrefIndex];
+ backrefLength = ovector[2 * backrefIndex + 1] - backrefStart;
+ } else
+ continue;
+
+ if (i - offset)
+ substitutedReplacement.append(replacement.characters() + offset, i - offset);
+ i += 1 + advance;
+ offset = i + 1;
+ if (backrefStart >= 0)
+ substitutedReplacement.append(source.characters() + backrefStart, backrefLength);
+ } while ((i = replacement.find('$', i + 1)) != notFound);
+
+ if (replacement.length() - offset)
+ substitutedReplacement.append(replacement.characters() + offset, replacement.length() - offset);
+
+ substitutedReplacement.shrinkToFit();
+ return UString::adopt(substitutedReplacement);
+}
+
+static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg)
+{
+ size_t i = replacement.find('$', 0);
+ if (UNLIKELY(i != notFound))
+ return substituteBackreferencesSlow(replacement, source, ovector, reg, i);
+ return replacement;
+}
+
+static inline int localeCompare(const UString& a, const UString& b)
+{
+ return Collator::userDefault()->collate(reinterpret_cast<const ::UChar*>(a.characters()), a.length(), reinterpret_cast<const ::UChar*>(b.characters()), b.length());
+}
+
+struct StringRange {
+public:
+ StringRange(int pos, int len)
+ : position(pos)
+ , length(len)
+ {
+ }
+
+ StringRange()
+ {
+ }
+
+ int position;
+ int length;
+};
+
+static ALWAYS_INLINE JSValue jsSpliceSubstrings(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount)
+{
+ if (rangeCount == 1) {
+ int sourceSize = source.length();
+ int position = substringRanges[0].position;
+ int length = substringRanges[0].length;
+ if (position <= 0 && length >= sourceSize)
+ return sourceVal;
+ // We could call UString::substr, but this would result in redundant checks
+ return jsString(exec, StringImpl::create(source.impl(), max(0, position), min(sourceSize, length)));
+ }
+
+ int totalLength = 0;
+ for (int i = 0; i < rangeCount; i++)
+ totalLength += substringRanges[i].length;
+
+ if (!totalLength)
+ return jsString(exec, "");
+
+ if (source.is8Bit()) {
+ LChar* buffer;
+ const LChar* sourceData = source.characters8();
+ RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
+ if (!impl)
+ return throwOutOfMemoryError(exec);
+
+ int bufferPos = 0;
+ for (int i = 0; i < rangeCount; i++) {
+ if (int srcLen = substringRanges[i].length) {
+ StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
+ bufferPos += srcLen;
+ }
+ }
+
+ return jsString(exec, impl.release());
+ }
+
+ UChar* buffer;
+ const UChar* sourceData = source.characters16();
+
+ RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
+ if (!impl)
+ return throwOutOfMemoryError(exec);
+
+ int bufferPos = 0;
+ for (int i = 0; i < rangeCount; i++) {
+ if (int srcLen = substringRanges[i].length) {
+ StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
+ bufferPos += srcLen;
+ }
+ }
+
+ return jsString(exec, impl.release());
+}
+
+static ALWAYS_INLINE JSValue jsSpliceSubstringsWithSeparators(ExecState* exec, JSString* sourceVal, const UString& source, const StringRange* substringRanges, int rangeCount, const UString* separators, int separatorCount)
+{
+ if (rangeCount == 1 && separatorCount == 0) {
+ int sourceSize = source.length();
+ int position = substringRanges[0].position;
+ int length = substringRanges[0].length;
+ if (position <= 0 && length >= sourceSize)
+ return sourceVal;
+ // We could call UString::substr, but this would result in redundant checks
+ return jsString(exec, StringImpl::create(source.impl(), max(0, position), min(sourceSize, length)));
+ }
+
+ int totalLength = 0;
+ bool allSeperators8Bit = true;
+ for (int i = 0; i < rangeCount; i++)
+ totalLength += substringRanges[i].length;
+ for (int i = 0; i < separatorCount; i++) {
+ totalLength += separators[i].length();
+ if (separators[i].length() && !separators[i].is8Bit())
+ allSeperators8Bit = false;
+ }
+
+ if (!totalLength)
+ return jsString(exec, "");
+
+ if (source.is8Bit() && allSeperators8Bit) {
+ LChar* buffer;
+ const LChar* sourceData = source.characters8();
+
+ RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
+ if (!impl)
+ return throwOutOfMemoryError(exec);
+
+ int maxCount = max(rangeCount, separatorCount);
+ int bufferPos = 0;
+ for (int i = 0; i < maxCount; i++) {
+ if (i < rangeCount) {
+ if (int srcLen = substringRanges[i].length) {
+ StringImpl::copyChars(buffer + bufferPos, sourceData + substringRanges[i].position, srcLen);
+ bufferPos += srcLen;
+ }
+ }
+ if (i < separatorCount) {
+ if (int sepLen = separators[i].length()) {
+ StringImpl::copyChars(buffer + bufferPos, separators[i].characters8(), sepLen);
+ bufferPos += sepLen;
+ }
+ }
+ }
+
+ return jsString(exec, impl.release());
+ }
+
+ UChar* buffer;
+ RefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(totalLength, buffer);
+ if (!impl)
+ return throwOutOfMemoryError(exec);
+
+ int maxCount = max(rangeCount, separatorCount);
+ int bufferPos = 0;
+ for (int i = 0; i < maxCount; i++) {
+ if (i < rangeCount) {
+ if (int srcLen = substringRanges[i].length) {
+ StringImpl::copyChars(buffer + bufferPos, source.characters() + substringRanges[i].position, srcLen);
+ bufferPos += srcLen;
+ }
+ }
+ if (i < separatorCount) {
+ if (int sepLen = separators[i].length()) {
+ StringImpl::copyChars(buffer + bufferPos, separators[i].characters(), sepLen);
+ bufferPos += sepLen;
+ }
+ }
+ }
+
+ return jsString(exec, impl.release());
+}
+
+static NEVER_INLINE EncodedJSValue replaceUsingRegExpSearch(ExecState* exec, JSString* string, JSValue searchValue, JSValue replaceValue)
+{
+ UString replacementString;
+ CallData callData;
+ CallType callType = getCallData(replaceValue, callData);
+ if (callType == CallTypeNone)
+ replacementString = replaceValue.toString(exec);
+
+ const UString& source = string->value(exec);
+ unsigned sourceLen = source.length();
+ if (exec->hadException())
+ return JSValue::encode(JSValue());
+ RegExp* regExp = asRegExpObject(searchValue)->regExp();
+ bool global = regExp->global();
+
+ RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
+
+ // Optimization for substring removal (replace with empty).
+ if (global && callType == CallTypeNone && !replacementString.length()) {
+ int lastIndex = 0;
+ unsigned startPosition = 0;
+
+ Vector<StringRange, 16> sourceRanges;
+ JSGlobalData* globalData = &exec->globalData();
+ while (true) {
+ int matchIndex;
+ int matchLen = 0;
+ int* ovector;
+ regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector);
+ if (matchIndex < 0)
+ break;
+
+ if (lastIndex < matchIndex)
+ sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+
+ lastIndex = matchIndex + matchLen;
+ startPosition = lastIndex;
+
+ // special case of empty match
+ if (!matchLen) {
+ startPosition++;
+ if (startPosition > sourceLen)
+ break;
+ }
+ }
+
+ if (!lastIndex)
+ return JSValue::encode(string);
+
+ if (static_cast<unsigned>(lastIndex) < sourceLen)
+ sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex));
+
+ return JSValue::encode(jsSpliceSubstrings(exec, string, source, sourceRanges.data(), sourceRanges.size()));
+ }
+
+ int lastIndex = 0;
+ unsigned startPosition = 0;
+
+ Vector<StringRange, 16> sourceRanges;
+ Vector<UString, 16> replacements;
+
+ // This is either a loop (if global is set) or a one-way (if not).
+ if (global && callType == CallTypeJS) {
+ // regExp->numSubpatterns() + 1 for pattern args, + 2 for match start and string
+ int argCount = regExp->numSubpatterns() + 1 + 2;
+ JSFunction* func = asFunction(replaceValue);
+ CachedCall cachedCall(exec, func, argCount);
+ if (exec->hadException())
+ return JSValue::encode(jsNull());
+ JSGlobalData* globalData = &exec->globalData();
+ if (source.is8Bit()) {
+ while (true) {
+ int matchIndex;
+ int matchLen = 0;
+ int* ovector;
+ regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector);
+ if (matchIndex < 0)
+ break;
+
+ sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+
+ int completeMatchStart = ovector[0];
+ unsigned i = 0;
+ for (; i < regExp->numSubpatterns() + 1; ++i) {
+ int matchStart = ovector[i * 2];
+ int matchLen = ovector[i * 2 + 1] - matchStart;
+
+ if (matchStart < 0)
+ cachedCall.setArgument(i, jsUndefined());
+ else
+ cachedCall.setArgument(i, jsSubstring8(globalData, source, matchStart, matchLen));
+ }
+
+ cachedCall.setArgument(i++, jsNumber(completeMatchStart));
+ cachedCall.setArgument(i++, string);
+
+ cachedCall.setThis(jsUndefined());
+ JSValue result = cachedCall.call();
+ if (LIKELY(result.isString()))
+ replacements.append(asString(result)->value(exec));
+ else
+ replacements.append(result.toString(cachedCall.newCallFrame(exec)));
+ if (exec->hadException())
+ break;
+
+ lastIndex = matchIndex + matchLen;
+ startPosition = lastIndex;
+
+ // special case of empty match
+ if (!matchLen) {
+ startPosition++;
+ if (startPosition > sourceLen)
+ break;
+ }
+ }
+ } else {
+ while (true) {
+ int matchIndex;
+ int matchLen = 0;
+ int* ovector;
+ regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector);
+ if (matchIndex < 0)
+ break;
+
+ sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+
+ int completeMatchStart = ovector[0];
+ unsigned i = 0;
+ for (; i < regExp->numSubpatterns() + 1; ++i) {
+ int matchStart = ovector[i * 2];
+ int matchLen = ovector[i * 2 + 1] - matchStart;
+
+ if (matchStart < 0)
+ cachedCall.setArgument(i, jsUndefined());
+ else
+ cachedCall.setArgument(i, jsSubstring(globalData, source, matchStart, matchLen));
+ }
+
+ cachedCall.setArgument(i++, jsNumber(completeMatchStart));
+ cachedCall.setArgument(i++, string);
+
+ cachedCall.setThis(jsUndefined());
+ JSValue result = cachedCall.call();
+ if (LIKELY(result.isString()))
+ replacements.append(asString(result)->value(exec));
+ else
+ replacements.append(result.toString(cachedCall.newCallFrame(exec)));
+ if (exec->hadException())
+ break;
+
+ lastIndex = matchIndex + matchLen;
+ startPosition = lastIndex;
+
+ // special case of empty match
+ if (!matchLen) {
+ startPosition++;
+ if (startPosition > sourceLen)
+ break;
+ }
+ }
+ }
+ } else {
+ JSGlobalData* globalData = &exec->globalData();
+ do {
+ int matchIndex;
+ int matchLen = 0;
+ int* ovector;
+ regExpConstructor->performMatch(*globalData, regExp, source, startPosition, matchIndex, matchLen, &ovector);
+ if (matchIndex < 0)
+ break;
+
+ if (callType != CallTypeNone) {
+ sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+
+ int completeMatchStart = ovector[0];
+ MarkedArgumentBuffer args;
+
+ for (unsigned i = 0; i < regExp->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(completeMatchStart));
+ args.append(string);
+
+ replacements.append(call(exec, replaceValue, callType, callData, jsUndefined(), args).toString(exec));
+ if (exec->hadException())
+ break;
+ } else {
+ int replLen = replacementString.length();
+ if (lastIndex < matchIndex || replLen) {
+ sourceRanges.append(StringRange(lastIndex, matchIndex - lastIndex));
+
+ if (replLen)
+ replacements.append(substituteBackreferences(replacementString, source, ovector, regExp));
+ else
+ replacements.append(UString());
+ }
+ }
+
+ lastIndex = matchIndex + matchLen;
+ startPosition = lastIndex;
+
+ // special case of empty match
+ if (!matchLen) {
+ startPosition++;
+ if (startPosition > sourceLen)
+ break;
+ }
+ } while (global);
+ }
+
+ if (!lastIndex && replacements.isEmpty())
+ return JSValue::encode(string);
+
+ if (static_cast<unsigned>(lastIndex) < sourceLen)
+ sourceRanges.append(StringRange(lastIndex, sourceLen - lastIndex));
+
+ return JSValue::encode(jsSpliceSubstringsWithSeparators(exec, string, source, sourceRanges.data(), sourceRanges.size(), replacements.data(), replacements.size()));
+}
+
+static NEVER_INLINE EncodedJSValue replaceUsingStringSearch(ExecState* exec, JSString* jsString, JSValue searchValue, JSValue replaceValue)
+{
+ const UString& string = jsString->value(exec);
+ UString searchString = searchValue.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ size_t matchStart = string.find(searchString);
+ if (matchStart == notFound)
+ return JSValue::encode(jsString);
+
+ CallData callData;
+ CallType callType = getCallData(replaceValue, callData);
+ if (callType != CallTypeNone) {
+ MarkedArgumentBuffer args;
+ args.append(jsSubstring(exec, string, matchStart, searchString.length()));
+ args.append(jsNumber(matchStart));
+ args.append(jsString);
+ replaceValue = call(exec, replaceValue, callType, callData, jsUndefined(), args);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ }
+
+ UString replaceString = replaceValue.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+
+ size_t matchEnd = matchStart + searchString.length();
+ int ovector[2] = { matchStart, matchEnd};
+ return JSValue::encode(JSC::jsString(exec, string.substringSharingImpl(0, matchStart), substituteBackreferences(replaceString, string, ovector, 0), string.substringSharingImpl(matchEnd)));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (!thisValue.isString()) {
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ thisValue = jsString(exec, thisValue.toString(exec));
+ }
+ JSString* string = asString(thisValue);
+ JSValue searchValue = exec->argument(0);
+ JSValue replaceValue = exec->argument(1);
+
+ if (searchValue.inherits(&RegExpObject::s_info))
+ return replaceUsingRegExpSearch(exec, string, searchValue, replaceValue);
+ return replaceUsingStringSearch(exec, string, searchValue, replaceValue);
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ // Also used for valueOf.
+
+ if (thisValue.isString())
+ return JSValue::encode(thisValue);
+
+ if (thisValue.inherits(&StringObject::s_info))
+ return JSValue::encode(asStringObject(thisValue)->internalValue());
+
+ return throwVMTypeError(exec);
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncCharAt(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ unsigned len = s.length();
+ JSValue a0 = exec->argument(0);
+ if (a0.isUInt32()) {
+ uint32_t i = a0.asUInt32();
+ if (i < len)
+ return JSValue::encode(jsSingleCharacterSubstring(exec, s, i));
+ return JSValue::encode(jsEmptyString(exec));
+ }
+ double dpos = a0.toInteger(exec);
+ if (dpos >= 0 && dpos < len)
+ return JSValue::encode(jsSingleCharacterSubstring(exec, s, static_cast<unsigned>(dpos)));
+ return JSValue::encode(jsEmptyString(exec));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncCharCodeAt(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ unsigned len = s.length();
+ JSValue a0 = exec->argument(0);
+ if (a0.isUInt32()) {
+ uint32_t i = a0.asUInt32();
+ if (i < len) {
+ if (s.is8Bit())
+ return JSValue::encode(jsNumber(s.characters8()[i]));
+ return JSValue::encode(jsNumber(s.characters16()[i]));
+ }
+ return JSValue::encode(jsNaN());
+ }
+ double dpos = a0.toInteger(exec);
+ if (dpos >= 0 && dpos < len)
+ return JSValue::encode(jsNumber(s[static_cast<int>(dpos)]));
+ return JSValue::encode(jsNaN());
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncConcat(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isString() && (exec->argumentCount() == 1)) {
+ JSValue v = exec->argument(0);
+ return JSValue::encode(v.isString()
+ ? jsString(exec, asString(thisValue), asString(v))
+ : jsString(exec, asString(thisValue), jsString(&exec->globalData(), v.toString(exec))));
+ }
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ return JSValue::encode(jsStringFromArguments(exec, thisValue));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncIndexOf(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ int len = s.length();
+
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(1);
+ UString u2 = a0.toString(exec);
+ int pos;
+ if (a1.isUndefined())
+ pos = 0;
+ else if (a1.isUInt32())
+ pos = min<uint32_t>(a1.asUInt32(), len);
+ else {
+ double dpos = a1.toInteger(exec);
+ if (dpos < 0)
+ dpos = 0;
+ else if (dpos > len)
+ dpos = len;
+ pos = static_cast<int>(dpos);
+ }
+
+ size_t result = s.find(u2, pos);
+ if (result == notFound)
+ return JSValue::encode(jsNumber(-1));
+ return JSValue::encode(jsNumber(result));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ int len = s.length();
+
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(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;
+
+ size_t result = s.reverseFind(u2, static_cast<unsigned>(dpos));
+ if (result == notFound)
+ return JSValue::encode(jsNumber(-1));
+ return JSValue::encode(jsNumber(result));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ JSGlobalData* globalData = &exec->globalData();
+
+ JSValue a0 = exec->argument(0);
+
+ RegExp* reg;
+ if (a0.inherits(&RegExpObject::s_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).
+ * Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
+ */
+ reg = RegExp::create(exec->globalData(), a0.isUndefined() ? UString("") : a0.toString(exec), NoFlags);
+ }
+ RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
+ int pos;
+ int matchLength = 0;
+ regExpConstructor->performMatch(*globalData, reg, s, 0, pos, matchLength);
+ if (!(reg->global())) {
+ // case without 'g' flag is handled like RegExp.prototype.exec
+ if (pos < 0)
+ return JSValue::encode(jsNull());
+ return JSValue::encode(regExpConstructor->arrayOfMatches(exec));
+ }
+
+ // return array of matches
+ MarkedArgumentBuffer list;
+ while (pos >= 0) {
+ list.append(jsSubstring(exec, s, pos, matchLength));
+ pos += matchLength == 0 ? 1 : matchLength;
+ regExpConstructor->performMatch(*globalData, reg, s, pos, pos, matchLength);
+ }
+ 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 JSValue::encode(jsNull());
+ }
+
+ return JSValue::encode(constructArray(exec, list));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ JSGlobalData* globalData = &exec->globalData();
+
+ JSValue a0 = exec->argument(0);
+
+ RegExp* reg;
+ if (a0.inherits(&RegExpObject::s_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).
+ * Per ECMA 15.10.4.1, if a0 is undefined substitute the empty string.
+ */
+ reg = RegExp::create(exec->globalData(), a0.isUndefined() ? UString("") : a0.toString(exec), NoFlags);
+ }
+ RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor();
+ int pos;
+ int matchLength = 0;
+ regExpConstructor->performMatch(*globalData, reg, s, 0, pos, matchLength);
+ return JSValue::encode(jsNumber(pos));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSlice(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ int len = s.length();
+
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(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 JSValue::encode(jsSubstring(exec, s, static_cast<unsigned>(from), static_cast<unsigned>(to) - static_cast<unsigned>(from)));
+ }
+
+ return JSValue::encode(jsEmptyString(exec));
+}
+
+// ES 5.1 - 15.5.4.14 String.prototype.split (separator, limit)
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec)
+{
+ // 1. Call CheckObjectCoercible passing the this value as its argument.
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull())
+ return throwVMTypeError(exec);
+
+ // 2. Let S be the result of calling ToString, giving it the this value as its argument.
+ // 6. Let s be the number of characters in S.
+ UString input = thisValue.toString(exec);
+
+ // 3. Let A be a new array created as if by the expression new Array()
+ // where Array is the standard built-in constructor with that name.
+ JSArray* result = constructEmptyArray(exec);
+
+ // 4. Let lengthA be 0.
+ unsigned resultLength = 0;
+
+ // 5. If limit is undefined, let lim = 2^32-1; else let lim = ToUint32(limit).
+ JSValue limitValue = exec->argument(1);
+ unsigned limit = limitValue.isUndefined() ? 0xFFFFFFFFu : limitValue.toUInt32(exec);
+
+ // 7. Let p = 0.
+ size_t position = 0;
+
+ // 8. If separator is a RegExp object (its [[Class]] is "RegExp"), let R = separator;
+ // otherwise let R = ToString(separator).
+ JSValue separatorValue = exec->argument(0);
+ if (separatorValue.inherits(&RegExpObject::s_info)) {
+ JSGlobalData* globalData = &exec->globalData();
+ RegExp* reg = asRegExpObject(separatorValue)->regExp();
+
+ // 9. If lim == 0, return A.
+ if (!limit)
+ return JSValue::encode(result);
+
+ // 10. If separator is undefined, then
+ if (separatorValue.isUndefined()) {
+ // a. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
+ // Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ result->methodTable()->putByIndex(result, exec, 0, jsStringWithReuse(exec, thisValue, input));
+ // b. Return A.
+ return JSValue::encode(result);
+ }
+
+ // 11. If s == 0, then
+ if (input.isEmpty()) {
+ // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
+ // b. If z is not failure, return A.
+ // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
+ // Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ // d. Return A.
+ if (reg->match(*globalData, input, 0) < 0)
+ result->methodTable()->putByIndex(result, exec, 0, jsStringWithReuse(exec, thisValue, input));
+ return JSValue::encode(result);
+ }
+
+ // 12. Let q = p.
+ size_t matchPosition = 0;
+ // 13. Repeat, while q != s
+ while (matchPosition < input.length()) {
+ // a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
+ Vector<int, 32> ovector;
+ int mpos = reg->match(*globalData, input, matchPosition, &ovector);
+ // b. If z is failure, then let q = q + 1.
+ if (mpos < 0)
+ break;
+ matchPosition = mpos;
+
+ // c. Else, z is not failure
+ // i. z must be a State. Let e be z's endIndex and let cap be z's captures array.
+ size_t matchEnd = ovector[1];
+
+ // ii. If e == p, then let q = q + 1.
+ if (matchEnd == position) {
+ ++matchPosition;
+ continue;
+ }
+ // iii. Else, e != p
+
+ // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
+ // through q (exclusive).
+ // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
+ // Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ result->methodTable()->putByIndex(result, exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
+ // 3. Increment lengthA by 1.
+ // 4. If lengthA == lim, return A.
+ if (++resultLength == limit)
+ return JSValue::encode(result);
+
+ // 5. Let p = e.
+ // 8. Let q = p.
+ position = matchEnd;
+ matchPosition = matchEnd;
+
+ // 6. Let i = 0.
+ // 7. Repeat, while i is not equal to the number of elements in cap.
+ // a Let i = i + 1.
+ for (unsigned i = 1; i <= reg->numSubpatterns(); ++i) {
+ // b Call the [[DefineOwnProperty]] internal method of A with arguments
+ // ToString(lengthA), Property Descriptor {[[Value]]: cap[i], [[Writable]]:
+ // true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ int sub = ovector[i * 2];
+ result->methodTable()->putByIndex(result, exec, resultLength, sub < 0 ? jsUndefined() : jsSubstring(exec, input, sub, ovector[i * 2 + 1] - sub));
+ // c Increment lengthA by 1.
+ // d If lengthA == lim, return A.
+ if (++resultLength == limit)
+ return JSValue::encode(result);
+ }
+ }
+ } else {
+ UString separator = separatorValue.toString(exec);
+
+ // 9. If lim == 0, return A.
+ if (!limit)
+ return JSValue::encode(result);
+
+ // 10. If separator is undefined, then
+ JSValue separatorValue = exec->argument(0);
+ if (separatorValue.isUndefined()) {
+ // a. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
+ // Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ result->methodTable()->putByIndex(result, exec, 0, jsStringWithReuse(exec, thisValue, input));
+ // b. Return A.
+ return JSValue::encode(result);
+ }
+
+ // 11. If s == 0, then
+ if (input.isEmpty()) {
+ // a. Call SplitMatch(S, 0, R) and let z be its MatchResult result.
+ // b. If z is not failure, return A.
+ // c. Call the [[DefineOwnProperty]] internal method of A with arguments "0",
+ // Property Descriptor {[[Value]]: S, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ // d. Return A.
+ if (!separator.isEmpty())
+ result->methodTable()->putByIndex(result, exec, 0, jsStringWithReuse(exec, thisValue, input));
+ return JSValue::encode(result);
+ }
+
+ // Optimized case for splitting on the empty string.
+ if (separator.isEmpty()) {
+ limit = std::min(limit, input.length());
+ // Zero limt/input length handled in steps 9/11 respectively, above.
+ ASSERT(limit);
+
+ do {
+ result->methodTable()->putByIndex(result, exec, position, jsSingleCharacterSubstring(exec, input, position));
+ } while (++position < limit);
+
+ return JSValue::encode(result);
+ }
+
+ // 12. Let q = p.
+ size_t matchPosition;
+ // 13. Repeat, while q != s
+ // a. Call SplitMatch(S, q, R) and let z be its MatchResult result.
+ // b. If z is failure, then let q = q+1.
+ // c. Else, z is not failure
+ while ((matchPosition = input.find(separator, position)) != notFound) {
+ // 1. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
+ // through q (exclusive).
+ // 2. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA),
+ // Property Descriptor {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ result->methodTable()->putByIndex(result, exec, resultLength, jsSubstring(exec, input, position, matchPosition - position));
+ // 3. Increment lengthA by 1.
+ // 4. If lengthA == lim, return A.
+ if (++resultLength == limit)
+ return JSValue::encode(result);
+
+ // 5. Let p = e.
+ // 8. Let q = p.
+ position = matchPosition + separator.length();
+ }
+ }
+
+ // 14. Let T be a String value equal to the substring of S consisting of the characters at positions p (inclusive)
+ // through s (exclusive).
+ // 15. Call the [[DefineOwnProperty]] internal method of A with arguments ToString(lengthA), Property Descriptor
+ // {[[Value]]: T, [[Writable]]: true, [[Enumerable]]: true, [[Configurable]]: true}, and false.
+ result->methodTable()->putByIndex(result, exec, resultLength++, jsSubstring(exec, input, position, input.length() - position));
+
+ // 16. Return A.
+ return JSValue::encode(result);
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstr(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ unsigned len;
+ JSString* jsString = 0;
+ UString uString;
+ if (thisValue.isString()) {
+ jsString = static_cast<JSString*>(thisValue.asCell());
+ len = jsString->length();
+ } else if (thisValue.isUndefinedOrNull()) {
+ // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ } else {
+ uString = thisValue.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ len = uString.length();
+ }
+
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(1);
+
+ double start = a0.toInteger(exec);
+ double length = a1.isUndefined() ? len : a1.toInteger(exec);
+ if (start >= len || length <= 0)
+ return JSValue::encode(jsEmptyString(exec));
+ if (start < 0) {
+ start += len;
+ if (start < 0)
+ start = 0;
+ }
+ if (start + length > len)
+ length = len - start;
+ unsigned substringStart = static_cast<unsigned>(start);
+ unsigned substringLength = static_cast<unsigned>(length);
+ if (jsString)
+ return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
+ return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ int len;
+ JSString* jsString = 0;
+ UString uString;
+ if (thisValue.isString()) {
+ jsString = static_cast<JSString*>(thisValue.asCell());
+ len = jsString->length();
+ } else if (thisValue.isUndefinedOrNull()) {
+ // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ } else {
+ uString = thisValue.toString(exec);
+ if (exec->hadException())
+ return JSValue::encode(jsUndefined());
+ len = uString.length();
+ }
+
+ JSValue a0 = exec->argument(0);
+ JSValue a1 = exec->argument(1);
+
+ double start = a0.toNumber(exec);
+ double end;
+ if (!(start >= 0)) // check for negative values or NaN
+ start = 0;
+ else if (start > len)
+ start = len;
+ if (a1.isUndefined())
+ end = len;
+ else {
+ end = a1.toNumber(exec);
+ if (!(end >= 0)) // check for negative values or NaN
+ end = 0;
+ else if (end > len)
+ end = len;
+ }
+ if (start > end) {
+ double temp = end;
+ end = start;
+ start = temp;
+ }
+ unsigned substringStart = static_cast<unsigned>(start);
+ unsigned substringLength = static_cast<unsigned>(end) - substringStart;
+ if (jsString)
+ return JSValue::encode(jsSubstring(exec, jsString, substringStart, substringLength));
+ return JSValue::encode(jsSubstring(exec, uString, substringStart, substringLength));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ JSString* sVal = thisValue.isString() ? asString(thisValue) : jsString(exec, thisValue.toString(exec));
+ const UString& s = sVal->value(exec);
+
+ int sSize = s.length();
+ if (!sSize)
+ return JSValue::encode(sVal);
+
+ StringImpl* ourImpl = s.impl();
+ RefPtr<StringImpl> lower = ourImpl->lower();
+ if (ourImpl == lower.get())
+ return JSValue::encode(sVal);
+ return JSValue::encode(jsString(exec, UString(lower.release())));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ JSString* sVal = thisValue.isString() ? asString(thisValue) : jsString(exec, thisValue.toString(exec));
+ const UString& s = sVal->value(exec);
+
+ int sSize = s.length();
+ if (!sSize)
+ return JSValue::encode(sVal);
+
+ const UChar* sData = s.characters();
+ 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 JSValue::encode(jsString(exec, UString::adopt(buffer)));
+
+ 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 JSValue::encode(sVal);
+ }
+ if (length == sSize) {
+ if (memcmp(buffer.data(), sData, length * sizeof(UChar)) == 0)
+ return JSValue::encode(sVal);
+ } else
+ buffer.resize(length);
+ return JSValue::encode(jsString(exec, UString::adopt(buffer)));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncLocaleCompare(ExecState* exec)
+{
+ if (exec->argumentCount() < 1)
+ return JSValue::encode(jsNumber(0));
+
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+
+ JSValue a0 = exec->argument(0);
+ return JSValue::encode(jsNumber(localeCompare(s, a0.toString(exec))));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncBig(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<big>", s, "</big>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSmall(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<small>", s, "</small>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncBlink(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<blink>", s, "</blink>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncBold(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<b>", s, "</b>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncFixed(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<tt>", s, "</tt>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncItalics(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<i>", s, "</i>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncStrike(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<strike>", s, "</strike>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSub(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<sub>", s, "</sub>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncSup(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<sup>", s, "</sup>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncFontcolor(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ JSValue a0 = exec->argument(0);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<font color=\"", a0.toString(exec), "\">", s, "</font>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ JSValue a0 = exec->argument(0);
+
+ uint32_t smallInteger;
+ if (a0.getUInt32(smallInteger) && smallInteger <= 9) {
+ unsigned stringSize = s.length();
+ unsigned bufferSize = 22 + stringSize;
+ UChar* buffer;
+ PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
+ if (!impl)
+ return JSValue::encode(jsUndefined());
+ buffer[0] = '<';
+ buffer[1] = 'f';
+ buffer[2] = 'o';
+ buffer[3] = 'n';
+ buffer[4] = 't';
+ buffer[5] = ' ';
+ buffer[6] = 's';
+ buffer[7] = 'i';
+ buffer[8] = 'z';
+ buffer[9] = 'e';
+ buffer[10] = '=';
+ buffer[11] = '"';
+ buffer[12] = '0' + smallInteger;
+ buffer[13] = '"';
+ buffer[14] = '>';
+ memcpy(&buffer[15], s.characters(), stringSize * sizeof(UChar));
+ buffer[15 + stringSize] = '<';
+ buffer[16 + stringSize] = '/';
+ buffer[17 + stringSize] = 'f';
+ buffer[18 + stringSize] = 'o';
+ buffer[19 + stringSize] = 'n';
+ buffer[20 + stringSize] = 't';
+ buffer[21 + stringSize] = '>';
+ return JSValue::encode(jsNontrivialString(exec, impl));
+ }
+
+ return JSValue::encode(jsMakeNontrivialString(exec, "<font size=\"", a0.toString(exec), "\">", s, "</font>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ JSValue a0 = exec->argument(0);
+ return JSValue::encode(jsMakeNontrivialString(exec, "<a name=\"", a0.toString(exec), "\">", s, "</a>"));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwVMTypeError(exec);
+ UString s = thisValue.toString(exec);
+ JSValue a0 = exec->argument(0);
+ UString linkText = a0.toString(exec);
+
+ unsigned linkTextSize = linkText.length();
+ unsigned stringSize = s.length();
+ unsigned bufferSize = 15 + linkTextSize + stringSize;
+ UChar* buffer;
+ PassRefPtr<StringImpl> impl = StringImpl::tryCreateUninitialized(bufferSize, buffer);
+ if (!impl)
+ return JSValue::encode(jsUndefined());
+ buffer[0] = '<';
+ buffer[1] = 'a';
+ buffer[2] = ' ';
+ buffer[3] = 'h';
+ buffer[4] = 'r';
+ buffer[5] = 'e';
+ buffer[6] = 'f';
+ buffer[7] = '=';
+ buffer[8] = '"';
+ memcpy(&buffer[9], linkText.characters(), linkTextSize * sizeof(UChar));
+ buffer[9 + linkTextSize] = '"';
+ buffer[10 + linkTextSize] = '>';
+ memcpy(&buffer[11 + linkTextSize], s.characters(), stringSize * sizeof(UChar));
+ buffer[11 + linkTextSize + stringSize] = '<';
+ buffer[12 + linkTextSize + stringSize] = '/';
+ buffer[13 + linkTextSize + stringSize] = 'a';
+ buffer[14 + linkTextSize + stringSize] = '>';
+ return JSValue::encode(jsNontrivialString(exec, impl));
+}
+
+enum {
+ TrimLeft = 1,
+ TrimRight = 2
+};
+
+static inline bool isTrimWhitespace(UChar c)
+{
+ return isStrWhiteSpace(c) || c == 0x200b;
+}
+
+static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind)
+{
+ if (thisValue.isUndefinedOrNull()) // CheckObjectCoercible
+ return throwTypeError(exec);
+ UString str = thisValue.toString(exec);
+ unsigned left = 0;
+ if (trimKind & TrimLeft) {
+ while (left < str.length() && isTrimWhitespace(str[left]))
+ left++;
+ }
+ unsigned right = str.length();
+ if (trimKind & TrimRight) {
+ while (right > left && isTrimWhitespace(str[right - 1]))
+ right--;
+ }
+
+ // Don't gc allocate a new string if we don't have to.
+ if (left == 0 && right == str.length() && thisValue.isString())
+ return thisValue;
+
+ return jsString(exec, str.substringSharingImpl(left, right - left));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(trimString(exec, thisValue, TrimLeft | TrimRight));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(trimString(exec, thisValue, TrimLeft));
+}
+
+EncodedJSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec)
+{
+ JSValue thisValue = exec->hostThisValue();
+ return JSValue::encode(trimString(exec, thisValue, TrimRight));
+}
+
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StringPrototype.h b/Source/JavaScriptCore/runtime/StringPrototype.h
new file mode 100644
index 000000000..113f21f2a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringPrototype.h
@@ -0,0 +1,63 @@
+/*
+ * 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 {
+ private:
+ StringPrototype(ExecState*, Structure*);
+
+ public:
+ typedef StringObject Base;
+
+ static StringPrototype* create(ExecState* exec, JSGlobalObject* globalObject, Structure* structure)
+ {
+ JSString* empty = jsEmptyString(exec);
+ StringPrototype* prototype = new (NotNull, allocateCell<StringPrototype>(*exec->heap())) StringPrototype(exec, structure);
+ prototype->finishCreation(exec, globalObject, empty);
+ return prototype;
+ }
+
+ static bool getOwnPropertySlot(JSCell*, ExecState*, const Identifier& propertyName, PropertySlot&);
+ static bool getOwnPropertyDescriptor(JSObject*, ExecState*, const Identifier&, PropertyDescriptor&);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype)
+ {
+ return Structure::create(globalData, globalObject, prototype, TypeInfo(ObjectType, StructureFlags), &s_info);
+ }
+
+ static const ClassInfo s_info;
+
+ protected:
+ void finishCreation(ExecState*, JSGlobalObject*, JSString*);
+ static const unsigned StructureFlags = OverridesGetOwnPropertySlot | StringObject::StructureFlags;
+
+ };
+
+} // namespace JSC
+
+#endif // StringPrototype_h
diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp
new file mode 100644
index 000000000..22b7367bc
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.cpp
@@ -0,0 +1,38 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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 "StringRecursionChecker.h"
+
+#include "Error.h"
+#include "ExceptionHelpers.h"
+
+namespace JSC {
+
+JSValue StringRecursionChecker::throwStackOverflowError()
+{
+ return throwError(m_exec, createStackOverflowError(m_exec));
+}
+
+JSValue StringRecursionChecker::emptyString()
+{
+ return jsEmptyString(m_exec);
+}
+
+}
diff --git a/Source/JavaScriptCore/runtime/StringRecursionChecker.h b/Source/JavaScriptCore/runtime/StringRecursionChecker.h
new file mode 100644
index 000000000..e3408b08b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StringRecursionChecker.h
@@ -0,0 +1,79 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * 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 StringRecursionChecker_h
+#define StringRecursionChecker_h
+
+#include "Interpreter.h"
+
+namespace JSC {
+
+class StringRecursionChecker {
+ WTF_MAKE_NONCOPYABLE(StringRecursionChecker);
+
+public:
+ StringRecursionChecker(ExecState*, JSObject* thisObject);
+ ~StringRecursionChecker();
+
+ JSValue earlyReturnValue() const; // 0 if everything is OK, value to return for failure cases
+
+private:
+ JSValue throwStackOverflowError();
+ JSValue emptyString();
+ JSValue performCheck();
+
+ ExecState* m_exec;
+ JSObject* m_thisObject;
+ JSValue m_earlyReturnValue;
+};
+
+inline JSValue StringRecursionChecker::performCheck()
+{
+ int size = m_exec->globalData().stringRecursionCheckVisitedObjects.size();
+ if (size >= MaxSmallThreadReentryDepth && size >= m_exec->globalData().maxReentryDepth)
+ return throwStackOverflowError();
+ bool alreadyVisited = !m_exec->globalData().stringRecursionCheckVisitedObjects.add(m_thisObject).second;
+ if (alreadyVisited)
+ return emptyString(); // Return empty string to avoid infinite recursion.
+ return JSValue(); // Indicate success.
+}
+
+inline StringRecursionChecker::StringRecursionChecker(ExecState* exec, JSObject* thisObject)
+ : m_exec(exec)
+ , m_thisObject(thisObject)
+ , m_earlyReturnValue(performCheck())
+{
+}
+
+inline JSValue StringRecursionChecker::earlyReturnValue() const
+{
+ return m_earlyReturnValue;
+}
+
+inline StringRecursionChecker::~StringRecursionChecker()
+{
+ if (m_earlyReturnValue)
+ return;
+ ASSERT(m_exec->globalData().stringRecursionCheckVisitedObjects.contains(m_thisObject));
+ m_exec->globalData().stringRecursionCheckVisitedObjects.remove(m_thisObject);
+}
+
+}
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/Structure.cpp b/Source/JavaScriptCore/runtime/Structure.cpp
new file mode 100644
index 000000000..dda8c73e9
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Structure.cpp
@@ -0,0 +1,851 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "Structure.h"
+
+#include "Identifier.h"
+#include "JSObject.h"
+#include "JSPropertyNameIterator.h"
+#include "Lookup.h"
+#include "PropertyNameArray.h"
+#include "StructureChain.h"
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Threading.h>
+
+#define DUMP_STRUCTURE_ID_STATISTICS 0
+
+#ifndef NDEBUG
+#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
+#else
+#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
+#endif
+
+using namespace std;
+using namespace WTF;
+
+#if DUMP_PROPERTYMAP_STATS
+
+int numProbes;
+int numCollisions;
+int numRehashes;
+int numRemoves;
+
+#endif
+
+namespace JSC {
+
+#if DUMP_STRUCTURE_ID_STATISTICS
+static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>);
+#endif
+
+bool StructureTransitionTable::contains(StringImpl* rep, unsigned attributes) const
+{
+ if (isUsingSingleSlot()) {
+ Structure* transition = singleTransition();
+ return transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes;
+ }
+ return map()->contains(make_pair(rep, attributes));
+}
+
+inline Structure* StructureTransitionTable::get(StringImpl* rep, unsigned attributes) const
+{
+ if (isUsingSingleSlot()) {
+ Structure* transition = singleTransition();
+ return (transition && transition->m_nameInPrevious == rep && transition->m_attributesInPrevious == attributes) ? transition : 0;
+ }
+ return map()->get(make_pair(rep, attributes));
+}
+
+inline void StructureTransitionTable::add(JSGlobalData& globalData, Structure* structure)
+{
+ if (isUsingSingleSlot()) {
+ Structure* existingTransition = singleTransition();
+
+ // This handles the first transition being added.
+ if (!existingTransition) {
+ setSingleTransition(globalData, structure);
+ return;
+ }
+
+ // This handles the second transition being added
+ // (or the first transition being despecified!)
+ setMap(new TransitionMap());
+ add(globalData, existingTransition);
+ }
+
+ // Add the structure to the map.
+
+ // Newer versions of the STL have an std::make_pair function that takes rvalue references.
+ // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
+ // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details
+ std::pair<TransitionMap::iterator, bool> result = map()->add(globalData, make_pair(structure->m_nameInPrevious, +structure->m_attributesInPrevious), structure);
+ if (!result.second) {
+ // There already is an entry! - we should only hit this when despecifying.
+ ASSERT(result.first.get().second->m_specificValueInPrevious);
+ ASSERT(!structure->m_specificValueInPrevious);
+ map()->set(result.first, structure);
+ }
+}
+
+void Structure::dumpStatistics()
+{
+#if DUMP_STRUCTURE_ID_STATISTICS
+ unsigned numberLeaf = 0;
+ unsigned numberUsingSingleSlot = 0;
+ unsigned numberSingletons = 0;
+ unsigned numberWithPropertyMaps = 0;
+ unsigned totalPropertyMapsSize = 0;
+
+ HashSet<Structure*>::const_iterator end = liveStructureSet.end();
+ for (HashSet<Structure*>::const_iterator it = liveStructureSet.begin(); it != end; ++it) {
+ Structure* structure = *it;
+
+ switch (structure->m_transitionTable.size()) {
+ case 0:
+ ++numberLeaf;
+ if (!structure->m_previous)
+ ++numberSingletons;
+ break;
+
+ case 1:
+ ++numberUsingSingleSlot;
+ break;
+ }
+
+ if (structure->m_propertyTable) {
+ ++numberWithPropertyMaps;
+ totalPropertyMapsSize += structure->m_propertyTable->sizeInMemory();
+ }
+ }
+
+ printf("Number of live Structures: %d\n", liveStructureSet.size());
+ printf("Number of Structures using the single item optimization for transition map: %d\n", numberUsingSingleSlot);
+ printf("Number of Structures that are leaf nodes: %d\n", numberLeaf);
+ printf("Number of Structures that singletons: %d\n", numberSingletons);
+ printf("Number of Structures with PropertyMaps: %d\n", numberWithPropertyMaps);
+
+ printf("Size of a single Structures: %d\n", static_cast<unsigned>(sizeof(Structure)));
+ printf("Size of sum of all property maps: %d\n", totalPropertyMapsSize);
+ printf("Size of average of all property maps: %f\n", static_cast<double>(totalPropertyMapsSize) / static_cast<double>(liveStructureSet.size()));
+#else
+ printf("Dumping Structure statistics is not enabled.\n");
+#endif
+}
+
+Structure::Structure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo)
+ : JSCell(globalData, globalData.structureStructure.get())
+ , m_typeInfo(typeInfo)
+ , m_globalObject(globalData, this, globalObject, WriteBarrier<JSGlobalObject>::MayBeNull)
+ , m_prototype(globalData, this, prototype)
+ , m_classInfo(classInfo)
+ , m_propertyStorageCapacity(typeInfo.isFinalObject() ? JSFinalObject_inlineStorageCapacity : JSNonFinalObject_inlineStorageCapacity)
+ , m_offset(noOffset)
+ , m_dictionaryKind(NoneDictionaryKind)
+ , m_isPinnedPropertyTable(false)
+ , m_hasGetterSetterProperties(false)
+ , m_hasNonEnumerableProperties(false)
+ , m_attributesInPrevious(0)
+ , m_specificFunctionThrashCount(0)
+ , m_preventExtensions(false)
+ , m_didTransition(false)
+ , m_staticFunctionReified(false)
+{
+}
+
+const ClassInfo Structure::s_info = { "Structure", 0, 0, 0, CREATE_METHOD_TABLE(Structure) };
+
+Structure::Structure(JSGlobalData& globalData)
+ : JSCell(CreatingEarlyCell)
+ , m_typeInfo(CompoundType, OverridesVisitChildren)
+ , m_prototype(globalData, this, jsNull())
+ , m_classInfo(&s_info)
+ , m_propertyStorageCapacity(0)
+ , m_offset(noOffset)
+ , m_dictionaryKind(NoneDictionaryKind)
+ , m_isPinnedPropertyTable(false)
+ , m_hasGetterSetterProperties(false)
+ , m_hasNonEnumerableProperties(false)
+ , m_attributesInPrevious(0)
+ , m_specificFunctionThrashCount(0)
+ , m_preventExtensions(false)
+ , m_didTransition(false)
+ , m_staticFunctionReified(false)
+{
+}
+
+Structure::Structure(JSGlobalData& globalData, const Structure* previous)
+ : JSCell(globalData, globalData.structureStructure.get())
+ , m_typeInfo(previous->typeInfo())
+ , m_prototype(globalData, this, previous->storedPrototype())
+ , m_classInfo(previous->m_classInfo)
+ , m_propertyStorageCapacity(previous->m_propertyStorageCapacity)
+ , m_offset(noOffset)
+ , m_dictionaryKind(previous->m_dictionaryKind)
+ , m_isPinnedPropertyTable(false)
+ , m_hasGetterSetterProperties(previous->m_hasGetterSetterProperties)
+ , m_hasNonEnumerableProperties(previous->m_hasNonEnumerableProperties)
+ , m_attributesInPrevious(0)
+ , m_specificFunctionThrashCount(previous->m_specificFunctionThrashCount)
+ , m_preventExtensions(previous->m_preventExtensions)
+ , m_didTransition(true)
+ , m_staticFunctionReified(previous->m_staticFunctionReified)
+{
+ if (previous->m_globalObject)
+ m_globalObject.set(globalData, this, previous->m_globalObject.get());
+}
+
+void Structure::destroy(JSCell* cell)
+{
+ jsCast<Structure*>(cell)->Structure::~Structure();
+}
+
+void Structure::materializePropertyMap(JSGlobalData& globalData)
+{
+ ASSERT(structure()->classInfo() == &s_info);
+ ASSERT(!m_propertyTable);
+
+ Vector<Structure*, 8> structures;
+ structures.append(this);
+
+ Structure* structure = this;
+
+ // Search for the last Structure with a property table.
+ while ((structure = structure->previousID())) {
+ if (structure->m_isPinnedPropertyTable) {
+ ASSERT(structure->m_propertyTable);
+ ASSERT(!structure->m_previous);
+
+ m_propertyTable = structure->m_propertyTable->copy(globalData, 0, m_offset + 1);
+ break;
+ }
+
+ structures.append(structure);
+ }
+
+ if (!m_propertyTable)
+ createPropertyMap(m_offset + 1);
+
+ for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) {
+ structure = structures[i];
+ PropertyMapEntry entry(globalData, this, structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious.get());
+ m_propertyTable->add(entry);
+ }
+}
+
+void Structure::growPropertyStorageCapacity()
+{
+ if (isUsingInlineStorage())
+ m_propertyStorageCapacity = JSObject::baseExternalStorageCapacity;
+ else
+ m_propertyStorageCapacity *= 2;
+}
+
+void Structure::despecifyDictionaryFunction(JSGlobalData& globalData, const Identifier& propertyName)
+{
+ StringImpl* rep = propertyName.impl();
+
+ materializePropertyMapIfNecessary(globalData);
+
+ ASSERT(isDictionary());
+ ASSERT(m_propertyTable);
+
+ PropertyMapEntry* entry = m_propertyTable->find(rep).first;
+ ASSERT(entry);
+ entry->specificValue.clear();
+}
+
+Structure* Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
+{
+ ASSERT(!structure->isDictionary());
+ ASSERT(structure->isObject());
+
+ if (Structure* existingTransition = structure->m_transitionTable.get(propertyName.impl(), attributes)) {
+ JSCell* specificValueInPrevious = existingTransition->m_specificValueInPrevious.get();
+ if (specificValueInPrevious && specificValueInPrevious != specificValue)
+ return 0;
+ ASSERT(existingTransition->m_offset != noOffset);
+ offset = existingTransition->m_offset;
+ return existingTransition;
+ }
+
+ return 0;
+}
+
+Structure* Structure::addPropertyTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset)
+{
+ // If we have a specific function, we may have got to this point if there is
+ // already a transition with the correct property name and attributes, but
+ // specialized to a different function. In this case we just want to give up
+ // and despecialize the transition.
+ // In this case we clear the value of specificFunction which will result
+ // in us adding a non-specific transition, and any subsequent lookup in
+ // Structure::addPropertyTransitionToExistingStructure will just use that.
+ if (specificValue && structure->m_transitionTable.contains(propertyName.impl(), attributes))
+ specificValue = 0;
+
+ ASSERT(!structure->isDictionary());
+ ASSERT(structure->isObject());
+ ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset));
+
+ if (structure->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
+ specificValue = 0;
+
+ if (structure->transitionCount() > s_maxTransitionLength) {
+ Structure* transition = toCacheableDictionaryTransition(globalData, structure);
+ ASSERT(structure != transition);
+ offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
+ if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
+ transition->growPropertyStorageCapacity();
+ return transition;
+ }
+
+ Structure* transition = create(globalData, structure);
+
+ transition->m_cachedPrototypeChain.setMayBeNull(globalData, transition, structure->m_cachedPrototypeChain.get());
+ transition->m_previous.set(globalData, transition, structure);
+ transition->m_nameInPrevious = propertyName.impl();
+ transition->m_attributesInPrevious = attributes;
+ transition->m_specificValueInPrevious.setMayBeNull(globalData, transition, specificValue);
+
+ if (structure->m_propertyTable) {
+ if (structure->m_isPinnedPropertyTable)
+ transition->m_propertyTable = structure->m_propertyTable->copy(globalData, transition, structure->m_propertyTable->size() + 1);
+ else
+ transition->m_propertyTable = structure->m_propertyTable.release();
+ } else {
+ if (structure->m_previous)
+ transition->materializePropertyMap(globalData);
+ else
+ transition->createPropertyMap();
+ }
+
+ offset = transition->putSpecificValue(globalData, propertyName, attributes, specificValue);
+ if (transition->propertyStorageSize() > transition->propertyStorageCapacity())
+ transition->growPropertyStorageCapacity();
+
+ transition->m_offset = offset;
+ structure->m_transitionTable.add(globalData, transition);
+ return transition;
+}
+
+Structure* Structure::removePropertyTransition(JSGlobalData& globalData, Structure* structure, const Identifier& propertyName, size_t& offset)
+{
+ ASSERT(!structure->isUncacheableDictionary());
+
+ Structure* transition = toUncacheableDictionaryTransition(globalData, structure);
+
+ offset = transition->remove(propertyName);
+
+ return transition;
+}
+
+Structure* Structure::changePrototypeTransition(JSGlobalData& globalData, Structure* structure, JSValue prototype)
+{
+ Structure* transition = create(globalData, structure);
+
+ transition->m_prototype.set(globalData, transition, prototype);
+
+ // Don't set m_offset, as one can not transition to this.
+
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+ transition->pin();
+
+ return transition;
+}
+
+Structure* Structure::despecifyFunctionTransition(JSGlobalData& globalData, Structure* structure, const Identifier& replaceFunction)
+{
+ ASSERT(structure->m_specificFunctionThrashCount < maxSpecificFunctionThrashCount);
+ Structure* transition = create(globalData, structure);
+
+ ++transition->m_specificFunctionThrashCount;
+
+ // Don't set m_offset, as one can not transition to this.
+
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+ transition->pin();
+
+ if (transition->m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
+ transition->despecifyAllFunctions(globalData);
+ else {
+ bool removed = transition->despecifyFunction(globalData, replaceFunction);
+ ASSERT_UNUSED(removed, removed);
+ }
+
+ return transition;
+}
+
+Structure* Structure::getterSetterTransition(JSGlobalData& globalData, Structure* structure)
+{
+ Structure* transition = create(globalData, structure);
+
+ // Don't set m_offset, as one can not transition to this.
+
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+ transition->pin();
+
+ return transition;
+}
+
+Structure* Structure::toDictionaryTransition(JSGlobalData& globalData, Structure* structure, DictionaryKind kind)
+{
+ ASSERT(!structure->isUncacheableDictionary());
+
+ Structure* transition = create(globalData, structure);
+
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+ transition->m_dictionaryKind = kind;
+ transition->pin();
+
+ return transition;
+}
+
+Structure* Structure::toCacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure)
+{
+ return toDictionaryTransition(globalData, structure, CachedDictionaryKind);
+}
+
+Structure* Structure::toUncacheableDictionaryTransition(JSGlobalData& globalData, Structure* structure)
+{
+ return toDictionaryTransition(globalData, structure, UncachedDictionaryKind);
+}
+
+// In future we may want to cache this transition.
+Structure* Structure::sealTransition(JSGlobalData& globalData, Structure* structure)
+{
+ Structure* transition = preventExtensionsTransition(globalData, structure);
+
+ if (transition->m_propertyTable) {
+ PropertyTable::iterator end = transition->m_propertyTable->end();
+ for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter)
+ iter->attributes |= DontDelete;
+ }
+
+ return transition;
+}
+
+// In future we may want to cache this transition.
+Structure* Structure::freezeTransition(JSGlobalData& globalData, Structure* structure)
+{
+ Structure* transition = preventExtensionsTransition(globalData, structure);
+
+ if (transition->m_propertyTable) {
+ PropertyTable::iterator end = transition->m_propertyTable->end();
+ for (PropertyTable::iterator iter = transition->m_propertyTable->begin(); iter != end; ++iter)
+ iter->attributes |= (DontDelete | ReadOnly);
+ }
+
+ return transition;
+}
+
+// In future we may want to cache this transition.
+Structure* Structure::preventExtensionsTransition(JSGlobalData& globalData, Structure* structure)
+{
+ Structure* transition = create(globalData, structure);
+
+ // Don't set m_offset, as one can not transition to this.
+
+ structure->materializePropertyMapIfNecessary(globalData);
+ transition->m_propertyTable = structure->copyPropertyTableForPinning(globalData, transition);
+ transition->m_preventExtensions = true;
+ transition->pin();
+
+ return transition;
+}
+
+// In future we may want to cache this property.
+bool Structure::isSealed(JSGlobalData& globalData)
+{
+ if (isExtensible())
+ return false;
+
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return true;
+
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
+ if ((iter->attributes & DontDelete) != DontDelete)
+ return false;
+ }
+ return true;
+}
+
+// In future we may want to cache this property.
+bool Structure::isFrozen(JSGlobalData& globalData)
+{
+ if (isExtensible())
+ return false;
+
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return true;
+
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
+ if ((iter->attributes & (DontDelete | ReadOnly)) != (DontDelete | ReadOnly))
+ return false;
+ }
+ return true;
+}
+
+Structure* Structure::flattenDictionaryStructure(JSGlobalData& globalData, JSObject* object)
+{
+ ASSERT(isDictionary());
+ if (isUncacheableDictionary()) {
+ ASSERT(m_propertyTable);
+
+ size_t propertyCount = m_propertyTable->size();
+ Vector<JSValue> values(propertyCount);
+
+ unsigned i = 0;
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter, ++i) {
+ values[i] = object->getDirectOffset(iter->offset);
+ // Update property table to have the new property offsets
+ iter->offset = i;
+ }
+
+ // Copy the original property values into their final locations
+ for (unsigned i = 0; i < propertyCount; i++)
+ object->putDirectOffset(globalData, i, values[i]);
+
+ m_propertyTable->clearDeletedOffsets();
+ }
+
+ m_dictionaryKind = NoneDictionaryKind;
+ return this;
+}
+
+size_t Structure::addPropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
+{
+ ASSERT(!m_enumerationCache);
+
+ if (m_specificFunctionThrashCount == maxSpecificFunctionThrashCount)
+ specificValue = 0;
+
+ materializePropertyMapIfNecessaryForPinning(globalData);
+
+ pin();
+
+ size_t offset = putSpecificValue(globalData, propertyName, attributes, specificValue);
+ if (propertyStorageSize() > propertyStorageCapacity())
+ growPropertyStorageCapacity();
+ return offset;
+}
+
+size_t Structure::removePropertyWithoutTransition(JSGlobalData& globalData, const Identifier& propertyName)
+{
+ ASSERT(isUncacheableDictionary());
+ ASSERT(!m_enumerationCache);
+
+ materializePropertyMapIfNecessaryForPinning(globalData);
+
+ pin();
+ size_t offset = remove(propertyName);
+ return offset;
+}
+
+void Structure::pin()
+{
+ ASSERT(m_propertyTable);
+ m_isPinnedPropertyTable = true;
+ m_previous.clear();
+ m_nameInPrevious.clear();
+}
+
+#if DUMP_PROPERTYMAP_STATS
+
+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
+
+#if !DO_PROPERTYMAP_CONSTENCY_CHECK
+
+inline void Structure::checkConsistency()
+{
+}
+
+#endif
+
+PassOwnPtr<PropertyTable> Structure::copyPropertyTable(JSGlobalData& globalData, Structure* owner)
+{
+ return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : 0);
+}
+
+PassOwnPtr<PropertyTable> Structure::copyPropertyTableForPinning(JSGlobalData& globalData, Structure* owner)
+{
+ return adoptPtr(m_propertyTable ? new PropertyTable(globalData, owner, *m_propertyTable) : new PropertyTable(m_offset == noOffset ? 0 : m_offset));
+}
+
+size_t Structure::get(JSGlobalData& globalData, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue)
+{
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return WTF::notFound;
+
+ PropertyMapEntry* entry = m_propertyTable->find(propertyName).first;
+ if (!entry)
+ return WTF::notFound;
+
+ attributes = entry->attributes;
+ specificValue = entry->specificValue.get();
+ return entry->offset;
+}
+
+bool Structure::despecifyFunction(JSGlobalData& globalData, const Identifier& propertyName)
+{
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return false;
+
+ ASSERT(!propertyName.isNull());
+ PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
+ if (!entry)
+ return false;
+
+ ASSERT(entry->specificValue);
+ entry->specificValue.clear();
+ return true;
+}
+
+void Structure::despecifyAllFunctions(JSGlobalData& globalData)
+{
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return;
+
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter)
+ iter->specificValue.clear();
+}
+
+size_t Structure::putSpecificValue(JSGlobalData& globalData, const Identifier& propertyName, unsigned attributes, JSCell* specificValue)
+{
+ ASSERT(!propertyName.isNull());
+ ASSERT(get(globalData, propertyName) == notFound);
+
+ checkConsistency();
+ if (attributes & DontEnum)
+ m_hasNonEnumerableProperties = true;
+
+ StringImpl* rep = propertyName.impl();
+
+ if (!m_propertyTable)
+ createPropertyMap();
+
+ unsigned newOffset;
+
+ if (m_propertyTable->hasDeletedOffset())
+ newOffset = m_propertyTable->getDeletedOffset();
+ else
+ newOffset = m_propertyTable->size();
+
+ m_propertyTable->add(PropertyMapEntry(globalData, this, rep, newOffset, attributes, specificValue));
+
+ checkConsistency();
+ return newOffset;
+}
+
+size_t Structure::remove(const Identifier& propertyName)
+{
+ ASSERT(!propertyName.isNull());
+
+ checkConsistency();
+
+ StringImpl* rep = propertyName.impl();
+
+ if (!m_propertyTable)
+ return notFound;
+
+ PropertyTable::find_iterator position = m_propertyTable->find(rep);
+ if (!position.first)
+ return notFound;
+
+ size_t offset = position.first->offset;
+
+ m_propertyTable->remove(position);
+ m_propertyTable->addDeletedOffset(offset);
+
+ checkConsistency();
+ return offset;
+}
+
+void Structure::createPropertyMap(unsigned capacity)
+{
+ ASSERT(!m_propertyTable);
+
+ checkConsistency();
+ m_propertyTable = adoptPtr(new PropertyTable(capacity));
+ checkConsistency();
+}
+
+void Structure::getPropertyNamesFromStructure(JSGlobalData& globalData, PropertyNameArray& propertyNames, EnumerationMode mode)
+{
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return;
+
+ bool knownUnique = !propertyNames.size();
+
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
+ ASSERT(m_hasNonEnumerableProperties || !(iter->attributes & DontEnum));
+ if (!(iter->attributes & DontEnum) || (mode == IncludeDontEnumProperties)) {
+ if (knownUnique)
+ propertyNames.addKnownUnique(iter->key);
+ else
+ propertyNames.add(iter->key);
+ }
+ }
+}
+
+void Structure::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ Structure* thisObject = jsCast<Structure*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ JSCell::visitChildren(thisObject, visitor);
+ if (thisObject->m_globalObject)
+ visitor.append(&thisObject->m_globalObject);
+ if (!thisObject->isObject())
+ thisObject->m_cachedPrototypeChain.clear();
+ else {
+ if (thisObject->m_prototype)
+ visitor.append(&thisObject->m_prototype);
+ if (thisObject->m_cachedPrototypeChain)
+ visitor.append(&thisObject->m_cachedPrototypeChain);
+ }
+ if (thisObject->m_previous)
+ visitor.append(&thisObject->m_previous);
+ if (thisObject->m_specificValueInPrevious)
+ visitor.append(&thisObject->m_specificValueInPrevious);
+ if (thisObject->m_enumerationCache)
+ visitor.append(&thisObject->m_enumerationCache);
+ if (thisObject->m_propertyTable) {
+ PropertyTable::iterator end = thisObject->m_propertyTable->end();
+ for (PropertyTable::iterator ptr = thisObject->m_propertyTable->begin(); ptr != end; ++ptr) {
+ if (ptr->specificValue)
+ visitor.append(&ptr->specificValue);
+ }
+ }
+}
+
+#if DO_PROPERTYMAP_CONSTENCY_CHECK
+
+void PropertyTable::checkConsistency()
+{
+ ASSERT(m_indexSize >= PropertyTable::MinimumTableSize);
+ ASSERT(m_indexMask);
+ ASSERT(m_indexSize == m_indexMask + 1);
+ ASSERT(!(m_indexSize & m_indexMask));
+
+ ASSERT(m_keyCount <= m_indexSize / 2);
+ ASSERT(m_keyCount + m_deletedCount <= m_indexSize / 2);
+ ASSERT(m_deletedCount <= m_indexSize / 4);
+
+ unsigned indexCount = 0;
+ unsigned deletedIndexCount = 0;
+ for (unsigned a = 0; a != m_indexSize; ++a) {
+ unsigned entryIndex = m_index[a];
+ if (entryIndex == PropertyTable::EmptyEntryIndex)
+ continue;
+ if (entryIndex == deletedEntryIndex()) {
+ ++deletedIndexCount;
+ continue;
+ }
+ ASSERT(entryIndex < deletedEntryIndex());
+ ASSERT(entryIndex - 1 <= usedCount());
+ ++indexCount;
+
+ for (unsigned b = a + 1; b != m_indexSize; ++b)
+ ASSERT(m_index[b] != entryIndex);
+ }
+ ASSERT(indexCount == m_keyCount);
+ ASSERT(deletedIndexCount == m_deletedCount);
+
+ ASSERT(!table()[deletedEntryIndex() - 1].key);
+
+ unsigned nonEmptyEntryCount = 0;
+ for (unsigned c = 0; c < usedCount(); ++c) {
+ StringImpl* rep = table()[c].key;
+ if (rep == PROPERTY_MAP_DELETED_ENTRY_KEY)
+ continue;
+ ++nonEmptyEntryCount;
+ unsigned i = rep->existingHash();
+ unsigned k = 0;
+ unsigned entryIndex;
+ while (1) {
+ entryIndex = m_index[i & m_indexMask];
+ ASSERT(entryIndex != PropertyTable::EmptyEntryIndex);
+ if (rep == table()[entryIndex - 1].key)
+ break;
+ if (k == 0)
+ k = 1 | doubleHash(rep->existingHash());
+ i += k;
+ }
+ ASSERT(entryIndex == c + 1);
+ }
+
+ ASSERT(nonEmptyEntryCount == m_keyCount);
+}
+
+void Structure::checkConsistency()
+{
+ if (!m_propertyTable)
+ return;
+
+ if (!m_hasNonEnumerableProperties) {
+ PropertyTable::iterator end = m_propertyTable->end();
+ for (PropertyTable::iterator iter = m_propertyTable->begin(); iter != end; ++iter) {
+ ASSERT(!(iter->attributes & DontEnum));
+ }
+ }
+
+ m_propertyTable->checkConsistency();
+}
+
+#endif // DO_PROPERTYMAP_CONSTENCY_CHECK
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/Structure.h b/Source/JavaScriptCore/runtime/Structure.h
new file mode 100644
index 000000000..70e968014
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Structure.h
@@ -0,0 +1,406 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Structure_h
+#define Structure_h
+
+#include "ClassInfo.h"
+#include "Identifier.h"
+#include "JSCell.h"
+#include "JSType.h"
+#include "JSValue.h"
+#include "PropertyMapHashTable.h"
+#include "PropertyNameArray.h"
+#include "Protect.h"
+#include "StructureTransitionTable.h"
+#include "JSTypeInfo.h"
+#include "UString.h"
+#include "Weak.h"
+#include <wtf/PassOwnPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+
+
+namespace JSC {
+
+ class PropertyNameArray;
+ class PropertyNameArrayData;
+ class StructureChain;
+ class SlotVisitor;
+
+ class Structure : public JSCell {
+ public:
+ friend class StructureTransitionTable;
+
+ typedef JSCell Base;
+
+ static Structure* create(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype, const TypeInfo& typeInfo, const ClassInfo* classInfo)
+ {
+ ASSERT(globalData.structureStructure);
+ ASSERT(classInfo);
+ Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, globalObject, prototype, typeInfo, classInfo);
+ structure->finishCreation(globalData);
+ return structure;
+ }
+
+ protected:
+ void finishCreation(JSGlobalData& globalData)
+ {
+ Base::finishCreation(globalData);
+ ASSERT(m_prototype);
+ ASSERT(m_prototype.isObject() || m_prototype.isNull());
+ }
+
+ void finishCreation(JSGlobalData& globalData, CreatingEarlyCellTag)
+ {
+ Base::finishCreation(globalData, this, CreatingEarlyCell);
+ ASSERT(m_prototype);
+ ASSERT(m_prototype.isNull());
+ ASSERT(!globalData.structureStructure);
+ }
+
+ public:
+ static void dumpStatistics();
+
+ static Structure* addPropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
+ static Structure* addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset);
+ static Structure* removePropertyTransition(JSGlobalData&, Structure*, const Identifier& propertyName, size_t& offset);
+ static Structure* changePrototypeTransition(JSGlobalData&, Structure*, JSValue prototype);
+ static Structure* despecifyFunctionTransition(JSGlobalData&, Structure*, const Identifier&);
+ static Structure* getterSetterTransition(JSGlobalData&, Structure*);
+ static Structure* toCacheableDictionaryTransition(JSGlobalData&, Structure*);
+ static Structure* toUncacheableDictionaryTransition(JSGlobalData&, Structure*);
+ static Structure* sealTransition(JSGlobalData&, Structure*);
+ static Structure* freezeTransition(JSGlobalData&, Structure*);
+ static Structure* preventExtensionsTransition(JSGlobalData&, Structure*);
+
+ bool isSealed(JSGlobalData&);
+ bool isFrozen(JSGlobalData&);
+ bool isExtensible() const { return !m_preventExtensions; }
+ bool didTransition() const { return m_didTransition; }
+
+ Structure* flattenDictionaryStructure(JSGlobalData&, JSObject*);
+
+ static void destroy(JSCell*);
+
+ // These should be used with caution.
+ size_t addPropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
+ size_t removePropertyWithoutTransition(JSGlobalData&, const Identifier& propertyName);
+ void setPrototypeWithoutTransition(JSGlobalData& globalData, JSValue prototype) { m_prototype.set(globalData, this, prototype); }
+
+ bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; }
+ bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; }
+
+ // Type accessors.
+ const TypeInfo& typeInfo() const { ASSERT(structure()->classInfo() == &s_info); return m_typeInfo; }
+ bool isObject() const { return typeInfo().isObject(); }
+
+
+ JSGlobalObject* globalObject() const { return m_globalObject.get(); }
+ void setGlobalObject(JSGlobalData& globalData, JSGlobalObject* globalObject) { m_globalObject.set(globalData, this, globalObject); }
+
+ JSValue storedPrototype() const { return m_prototype.get(); }
+ JSValue prototypeForLookup(ExecState*) const;
+ StructureChain* prototypeChain(ExecState*) const;
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ Structure* previousID() const { ASSERT(structure()->classInfo() == &s_info); return m_previous.get(); }
+ bool transitivelyTransitionedFrom(Structure* structureToFind);
+
+ void growPropertyStorageCapacity();
+ unsigned propertyStorageCapacity() const { ASSERT(structure()->classInfo() == &s_info); return m_propertyStorageCapacity; }
+ unsigned propertyStorageSize() const { ASSERT(structure()->classInfo() == &s_info); return (m_propertyTable ? m_propertyTable->propertyStorageSize() : static_cast<unsigned>(m_offset + 1)); }
+ bool isUsingInlineStorage() const;
+
+ size_t get(JSGlobalData&, const Identifier& propertyName);
+ size_t get(JSGlobalData&, const UString& name);
+ size_t get(JSGlobalData&, StringImpl* propertyName, unsigned& attributes, JSCell*& specificValue);
+ size_t get(JSGlobalData& globalData, const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue)
+ {
+ ASSERT(!propertyName.isNull());
+ ASSERT(structure()->classInfo() == &s_info);
+ return get(globalData, propertyName.impl(), attributes, specificValue);
+ }
+
+ bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; }
+ void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; }
+
+ bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; }
+
+ bool isEmpty() const { return m_propertyTable ? m_propertyTable->isEmpty() : m_offset == noOffset; }
+
+ void despecifyDictionaryFunction(JSGlobalData&, const Identifier& propertyName);
+ void disableSpecificFunctionTracking() { m_specificFunctionThrashCount = maxSpecificFunctionThrashCount; }
+
+ void setEnumerationCache(JSGlobalData&, JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h.
+ JSPropertyNameIterator* enumerationCache(); // Defined in JSPropertyNameIterator.h.
+ void getPropertyNamesFromStructure(JSGlobalData&, PropertyNameArray&, EnumerationMode);
+
+ bool staticFunctionsReified()
+ {
+ return m_staticFunctionReified;
+ }
+
+ void setStaticFunctionsReified()
+ {
+ m_staticFunctionReified = true;
+ }
+
+ const ClassInfo* classInfo() const { return m_classInfo; }
+
+ static ptrdiff_t prototypeOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_prototype);
+ }
+
+ static ptrdiff_t typeInfoFlagsOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::flagsOffset();
+ }
+
+ static ptrdiff_t typeInfoTypeOffset()
+ {
+ return OBJECT_OFFSETOF(Structure, m_typeInfo) + TypeInfo::typeOffset();
+ }
+
+ static Structure* createStructure(JSGlobalData& globalData)
+ {
+ ASSERT(!globalData.structureStructure);
+ Structure* structure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData);
+ structure->finishCreation(globalData, CreatingEarlyCell);
+ return structure;
+ }
+
+ static JS_EXPORTDATA const ClassInfo s_info;
+
+ private:
+ Structure(JSGlobalData&, JSGlobalObject*, JSValue prototype, const TypeInfo&, const ClassInfo*);
+ Structure(JSGlobalData&);
+ Structure(JSGlobalData&, const Structure*);
+
+ static Structure* create(JSGlobalData& globalData, const Structure* structure)
+ {
+ ASSERT(globalData.structureStructure);
+ Structure* newStructure = new (NotNull, allocateCell<Structure>(globalData.heap)) Structure(globalData, structure);
+ newStructure->finishCreation(globalData);
+ return newStructure;
+ }
+
+ typedef enum {
+ NoneDictionaryKind = 0,
+ CachedDictionaryKind = 1,
+ UncachedDictionaryKind = 2
+ } DictionaryKind;
+ static Structure* toDictionaryTransition(JSGlobalData&, Structure*, DictionaryKind);
+
+ size_t putSpecificValue(JSGlobalData&, const Identifier& propertyName, unsigned attributes, JSCell* specificValue);
+ size_t remove(const Identifier& propertyName);
+
+ void createPropertyMap(unsigned keyCount = 0);
+ void checkConsistency();
+
+ bool despecifyFunction(JSGlobalData&, const Identifier&);
+ void despecifyAllFunctions(JSGlobalData&);
+
+ PassOwnPtr<PropertyTable> copyPropertyTable(JSGlobalData&, Structure* owner);
+ PassOwnPtr<PropertyTable> copyPropertyTableForPinning(JSGlobalData&, Structure* owner);
+ void materializePropertyMap(JSGlobalData&);
+ void materializePropertyMapIfNecessary(JSGlobalData& globalData)
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ if (!m_propertyTable && m_previous)
+ materializePropertyMap(globalData);
+ }
+ void materializePropertyMapIfNecessaryForPinning(JSGlobalData& globalData)
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ if (!m_propertyTable)
+ materializePropertyMap(globalData);
+ }
+
+ int transitionCount() const
+ {
+ // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both.
+ return m_offset == noOffset ? 0 : m_offset + 1;
+ }
+
+ bool isValid(ExecState*, StructureChain* cachedPrototypeChain) const;
+
+ void pin();
+
+ static const int s_maxTransitionLength = 64;
+
+ static const int noOffset = -1;
+
+ static const unsigned maxSpecificFunctionThrashCount = 3;
+
+ TypeInfo m_typeInfo;
+
+ WriteBarrier<JSGlobalObject> m_globalObject;
+ WriteBarrier<Unknown> m_prototype;
+ mutable WriteBarrier<StructureChain> m_cachedPrototypeChain;
+
+ WriteBarrier<Structure> m_previous;
+ RefPtr<StringImpl> m_nameInPrevious;
+ WriteBarrier<JSCell> m_specificValueInPrevious;
+
+ const ClassInfo* m_classInfo;
+
+ StructureTransitionTable m_transitionTable;
+
+ WriteBarrier<JSPropertyNameIterator> m_enumerationCache;
+
+ OwnPtr<PropertyTable> m_propertyTable;
+
+ uint32_t m_propertyStorageCapacity;
+
+ // m_offset does not account for anonymous slots
+ int m_offset;
+
+ unsigned m_dictionaryKind : 2;
+ bool m_isPinnedPropertyTable : 1;
+ bool m_hasGetterSetterProperties : 1;
+ bool m_hasNonEnumerableProperties : 1;
+ unsigned m_attributesInPrevious : 7;
+ unsigned m_specificFunctionThrashCount : 2;
+ unsigned m_preventExtensions : 1;
+ unsigned m_didTransition : 1;
+ unsigned m_staticFunctionReified;
+ };
+
+ inline size_t Structure::get(JSGlobalData& globalData, const Identifier& propertyName)
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return notFound;
+
+ PropertyMapEntry* entry = m_propertyTable->find(propertyName.impl()).first;
+ return entry ? entry->offset : notFound;
+ }
+
+ inline size_t Structure::get(JSGlobalData& globalData, const UString& name)
+ {
+ ASSERT(structure()->classInfo() == &s_info);
+ materializePropertyMapIfNecessary(globalData);
+ if (!m_propertyTable)
+ return notFound;
+
+ PropertyMapEntry* entry = m_propertyTable->findWithString(name.impl()).first;
+ return entry ? entry->offset : notFound;
+ }
+
+ inline bool JSCell::isObject() const
+ {
+ return m_structure->isObject();
+ }
+
+ inline bool JSCell::isString() const
+ {
+ return m_structure->typeInfo().type() == StringType;
+ }
+
+ inline bool JSCell::isGetterSetter() const
+ {
+ return m_structure->typeInfo().type() == GetterSetterType;
+ }
+
+ inline bool JSCell::isAPIValueWrapper() const
+ {
+ return m_structure->typeInfo().type() == APIValueWrapperType;
+ }
+
+ inline void JSCell::setStructure(JSGlobalData& globalData, Structure* structure)
+ {
+ ASSERT(structure->typeInfo().overridesVisitChildren() == this->structure()->typeInfo().overridesVisitChildren());
+ ASSERT(structure->classInfo() == m_structure->classInfo());
+ m_structure.set(globalData, this, structure);
+ }
+
+ inline const ClassInfo* JSCell::validatedClassInfo() const
+ {
+#if ENABLE(GC_VALIDATION)
+ ASSERT(m_structure.unvalidatedGet()->classInfo() == m_classInfo);
+#else
+ ASSERT(m_structure->classInfo() == m_classInfo);
+#endif
+ return m_classInfo;
+ }
+
+ ALWAYS_INLINE void MarkStack::internalAppend(JSCell* cell)
+ {
+ ASSERT(!m_isCheckingForDefaultMarkViolation);
+#if ENABLE(GC_VALIDATION)
+ validate(cell);
+#endif
+ m_visitCount++;
+ if (Heap::testAndSetMarked(cell) || !cell->structure())
+ return;
+
+ // Should never attempt to mark something that is zapped.
+ ASSERT(!cell->isZapped());
+
+ m_stack.append(cell);
+ }
+
+ inline StructureTransitionTable::Hash::Key StructureTransitionTable::keyForWeakGCMapFinalizer(void*, Structure* structure)
+ {
+ // Newer versions of the STL have an std::make_pair function that takes rvalue references.
+ // When either of the parameters are bitfields, the C++ compiler will try to bind them as lvalues, which is invalid. To work around this, use unary "+" to make the parameter an rvalue.
+ // See https://bugs.webkit.org/show_bug.cgi?id=59261 for more details.
+ return Hash::Key(structure->m_nameInPrevious.get(), +structure->m_attributesInPrevious);
+ }
+
+ inline bool Structure::transitivelyTransitionedFrom(Structure* structureToFind)
+ {
+ for (Structure* current = this; current; current = current->previousID()) {
+ if (current == structureToFind)
+ return true;
+ }
+ return false;
+ }
+
+ inline JSCell::JSCell(JSGlobalData& globalData, Structure* structure)
+ : m_classInfo(structure->classInfo())
+ , m_structure(globalData, this, structure)
+ {
+ }
+
+ inline void JSCell::finishCreation(JSGlobalData& globalData, Structure* structure, CreatingEarlyCellTag)
+ {
+#if ENABLE(GC_VALIDATION)
+ ASSERT(globalData.isInitializingObject());
+ globalData.setInitializingObject(false);
+ if (structure)
+#endif
+ m_structure.setEarlyValue(globalData, this, structure);
+ m_classInfo = structure->classInfo();
+ // Very first set of allocations won't have a real structure.
+ ASSERT(m_structure || !globalData.structureStructure);
+ }
+
+} // namespace JSC
+
+#endif // Structure_h
diff --git a/Source/JavaScriptCore/runtime/StructureChain.cpp b/Source/JavaScriptCore/runtime/StructureChain.cpp
new file mode 100644
index 000000000..afb2d9501
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StructureChain.cpp
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "StructureChain.h"
+
+#include "JSObject.h"
+#include "Structure.h"
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+ClassInfo StructureChain::s_info = { "StructureChain", 0, 0, 0, CREATE_METHOD_TABLE(StructureChain) };
+
+StructureChain::StructureChain(JSGlobalData& globalData, Structure* structure)
+ : JSCell(globalData, structure)
+{
+}
+
+void StructureChain::destroy(JSCell* cell)
+{
+ jsCast<StructureChain*>(cell)->StructureChain::~StructureChain();
+}
+
+void StructureChain::visitChildren(JSCell* cell, SlotVisitor& visitor)
+{
+ StructureChain* thisObject = jsCast<StructureChain*>(cell);
+ ASSERT_GC_OBJECT_INHERITS(thisObject, &s_info);
+ ASSERT(thisObject->structure()->typeInfo().overridesVisitChildren());
+ size_t i = 0;
+ while (thisObject->m_vector[i])
+ visitor.append(&thisObject->m_vector[i++]);
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/StructureChain.h b/Source/JavaScriptCore/runtime/StructureChain.h
new file mode 100644
index 000000000..df7a37fa7
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StructureChain.h
@@ -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 COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StructureChain_h
+#define StructureChain_h
+
+#include "JSCell.h"
+#include "JSObject.h"
+#include "Structure.h"
+
+#include <wtf/OwnArrayPtr.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefCounted.h>
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+ class Structure;
+
+ class StructureChain : public JSCell {
+ friend class JIT;
+
+ public:
+ typedef JSCell Base;
+
+ static StructureChain* create(JSGlobalData& globalData, Structure* head)
+ {
+ StructureChain* chain = new (NotNull, allocateCell<StructureChain>(globalData.heap)) StructureChain(globalData, globalData.structureChainStructure.get());
+ chain->finishCreation(globalData, head);
+ return chain;
+ }
+ WriteBarrier<Structure>* head() { return m_vector.get(); }
+ static void visitChildren(JSCell*, SlotVisitor&);
+
+ static Structure* createStructure(JSGlobalData& globalData, JSGlobalObject* globalObject, JSValue prototype) { return Structure::create(globalData, globalObject, prototype, TypeInfo(CompoundType, OverridesVisitChildren), &s_info); }
+
+ static ClassInfo s_info;
+
+ protected:
+ void finishCreation(JSGlobalData& globalData, Structure* head)
+ {
+ Base::finishCreation(globalData);
+ size_t size = 0;
+ for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure())
+ ++size;
+
+ m_vector = adoptArrayPtr(new WriteBarrier<Structure>[size + 1]);
+
+ size_t i = 0;
+ for (Structure* current = head; current; current = current->storedPrototype().isNull() ? 0 : asObject(current->storedPrototype())->structure())
+ m_vector[i++].set(globalData, this, current);
+ }
+
+ private:
+ StructureChain(JSGlobalData&, Structure*);
+ static void destroy(JSCell*);
+ OwnArrayPtr<WriteBarrier<Structure> > m_vector;
+ };
+
+} // namespace JSC
+
+#endif // StructureChain_h
diff --git a/Source/JavaScriptCore/runtime/StructureTransitionTable.h b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
new file mode 100644
index 000000000..536237a33
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/StructureTransitionTable.h
@@ -0,0 +1,172 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef StructureTransitionTable_h
+#define StructureTransitionTable_h
+
+#include "UString.h"
+#include "WeakGCMap.h"
+#include <wtf/HashFunctions.h>
+#include <wtf/HashTraits.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+class Structure;
+
+class StructureTransitionTable {
+ static const intptr_t UsingSingleSlotFlag = 1;
+
+ struct Hash {
+ typedef std::pair<RefPtr<StringImpl>, unsigned> Key;
+ static unsigned hash(const Key& p)
+ {
+ return p.first->existingHash();
+ }
+
+ static bool equal(const Key& a, const Key& b)
+ {
+ return a == b;
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+
+ struct HashTraits {
+ typedef WTF::HashTraits<RefPtr<StringImpl> > 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 const int minimumTableSize = FirstTraits::minimumTableSize;
+
+ static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); }
+ static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); }
+ };
+
+ struct WeakGCMapFinalizerCallback {
+ static void* finalizerContextFor(Hash::Key)
+ {
+ return 0;
+ }
+
+ static inline Hash::Key keyForFinalizer(void* context, Structure* structure)
+ {
+ return keyForWeakGCMapFinalizer(context, structure);
+ }
+ };
+
+ typedef WeakGCMap<Hash::Key, Structure, WeakGCMapFinalizerCallback, Hash, HashTraits> TransitionMap;
+
+ static Hash::Key keyForWeakGCMapFinalizer(void* context, Structure*);
+
+public:
+ StructureTransitionTable()
+ : m_data(UsingSingleSlotFlag)
+ {
+ }
+
+ ~StructureTransitionTable()
+ {
+ if (!isUsingSingleSlot()) {
+ delete map();
+ return;
+ }
+
+ HandleSlot slot = this->slot();
+ if (!slot)
+ return;
+ HandleHeap::heapFor(slot)->deallocate(slot);
+ }
+
+ inline void add(JSGlobalData&, Structure*);
+ inline bool contains(StringImpl* rep, unsigned attributes) const;
+ inline Structure* get(StringImpl* rep, unsigned attributes) const;
+
+private:
+ bool isUsingSingleSlot() const
+ {
+ return m_data & UsingSingleSlotFlag;
+ }
+
+ TransitionMap* map() const
+ {
+ ASSERT(!isUsingSingleSlot());
+ return reinterpret_cast<TransitionMap*>(m_data);
+ }
+
+ HandleSlot slot() const
+ {
+ ASSERT(isUsingSingleSlot());
+ return reinterpret_cast<HandleSlot>(m_data & ~UsingSingleSlotFlag);
+ }
+
+ void setMap(TransitionMap* map)
+ {
+ ASSERT(isUsingSingleSlot());
+
+ if (HandleSlot slot = this->slot())
+ HandleHeap::heapFor(slot)->deallocate(slot);
+
+ // This implicitly clears the flag that indicates we're using a single transition
+ m_data = reinterpret_cast<intptr_t>(map);
+
+ ASSERT(!isUsingSingleSlot());
+ }
+
+ Structure* singleTransition() const
+ {
+ ASSERT(isUsingSingleSlot());
+ if (HandleSlot slot = this->slot()) {
+ if (*slot)
+ return reinterpret_cast<Structure*>(slot->asCell());
+ }
+ return 0;
+ }
+
+ void setSingleTransition(JSGlobalData& globalData, Structure* structure)
+ {
+ ASSERT(isUsingSingleSlot());
+ HandleSlot slot = this->slot();
+ if (!slot) {
+ slot = globalData.heap.handleHeap()->allocate();
+ HandleHeap::heapFor(slot)->makeWeak(slot, 0, 0);
+ m_data = reinterpret_cast<intptr_t>(slot) | UsingSingleSlotFlag;
+ }
+ HandleHeap::heapFor(slot)->writeBarrier(slot, reinterpret_cast<JSCell*>(structure));
+ *slot = reinterpret_cast<JSCell*>(structure);
+ }
+
+ intptr_t m_data;
+};
+
+} // namespace JSC
+
+#endif // StructureTransitionTable_h
diff --git a/Source/JavaScriptCore/runtime/SymbolTable.h b/Source/JavaScriptCore/runtime/SymbolTable.h
new file mode 100644
index 000000000..81731222b
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/SymbolTable.h
@@ -0,0 +1,133 @@
+/*
+ * 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>
+#include <wtf/HashTraits.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 : HashTraits<SymbolTableEntry> {
+ static const bool emptyValueIsZero = true;
+ static const bool needsDestruction = false;
+ };
+
+ typedef HashMap<RefPtr<StringImpl>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<StringImpl> >, SymbolTableIndexHashTraits> SymbolTable;
+
+ class SharedSymbolTable : public SymbolTable, public RefCounted<SharedSymbolTable> {
+ WTF_MAKE_FAST_ALLOCATED;
+ public:
+ static PassRefPtr<SharedSymbolTable> create() { return adoptRef(new SharedSymbolTable); }
+ private:
+ SharedSymbolTable() { deprecatedTurnOffVerifier(); }
+ };
+
+} // namespace JSC
+
+#endif // SymbolTable_h
diff --git a/Source/JavaScriptCore/runtime/Terminator.h b/Source/JavaScriptCore/runtime/Terminator.h
new file mode 100644
index 000000000..6b0f2366f
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Terminator.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2010 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Google Inc. ("Google") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Terminator_h
+#define Terminator_h
+
+namespace JSC {
+
+class Terminator {
+public:
+ Terminator() : m_shouldTerminate(false) { }
+
+ void terminateSoon() { m_shouldTerminate = true; }
+ bool shouldTerminate() const { return m_shouldTerminate; }
+
+private:
+ bool m_shouldTerminate;
+};
+
+} // namespace JSC
+
+#endif // Terminator_h
diff --git a/Source/JavaScriptCore/runtime/TimeoutChecker.cpp b/Source/JavaScriptCore/runtime/TimeoutChecker.cpp
new file mode 100644
index 000000000..3065c99ed
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TimeoutChecker.cpp
@@ -0,0 +1,142 @@
+/*
+ * Copyright (C) 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Cameron Zwarich <cwzwarich@uwaterloo.ca>
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "TimeoutChecker.h"
+
+#include "CallFrame.h"
+#include "JSGlobalObject.h"
+
+#if OS(DARWIN)
+#include <mach/mach.h>
+#elif OS(WINDOWS)
+#include <windows.h>
+#else
+#include "CurrentTime.h"
+#endif
+
+using namespace std;
+
+namespace JSC {
+
+// Number of ticks before the first timeout check is done.
+static const int ticksUntilFirstCheck = 1024;
+
+// Number of milliseconds between each timeout check.
+static const int intervalBetweenChecks = 1000;
+
+// Returns the time the current thread has spent executing, in milliseconds.
+static inline unsigned getCPUTime()
+{
+#if OS(DARWIN)
+ mach_msg_type_number_t infoCount = THREAD_BASIC_INFO_COUNT;
+ thread_basic_info_data_t info;
+
+ // Get thread information
+ mach_port_t threadPort = mach_thread_self();
+ thread_info(threadPort, THREAD_BASIC_INFO, reinterpret_cast<thread_info_t>(&info), &infoCount);
+ mach_port_deallocate(mach_task_self(), threadPort);
+
+ unsigned time = info.user_time.seconds * 1000 + info.user_time.microseconds / 1000;
+ time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000;
+
+ return time;
+#elif OS(WINDOWS)
+ union {
+ FILETIME fileTime;
+ unsigned long long fileTimeAsLong;
+ } userTime, kernelTime;
+
+ // GetThreadTimes won't accept NULL arguments so we pass these even though
+ // they're not used.
+ FILETIME creationTime, exitTime;
+
+ GetThreadTimes(GetCurrentThread(), &creationTime, &exitTime, &kernelTime.fileTime, &userTime.fileTime);
+
+ return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000;
+#else
+ // FIXME: We should return the time the current thread has spent executing.
+
+ // use a relative time from first call in order to avoid an overflow
+ static double firstTime = currentTime();
+ return static_cast<unsigned> ((currentTime() - firstTime) * 1000);
+#endif
+}
+
+TimeoutChecker::TimeoutChecker()
+ : m_timeoutInterval(0)
+ , m_startCount(0)
+{
+ reset();
+}
+
+void TimeoutChecker::reset()
+{
+ m_ticksUntilNextCheck = ticksUntilFirstCheck;
+ m_timeAtLastCheck = 0;
+ m_timeExecuting = 0;
+}
+
+bool TimeoutChecker::didTimeOut(ExecState* exec)
+{
+ unsigned currentTime = getCPUTime();
+
+ if (!m_timeAtLastCheck) {
+ // Suspicious amount of looping in a script -- start timing it
+ m_timeAtLastCheck = currentTime;
+ return false;
+ }
+
+ unsigned timeDiff = currentTime - m_timeAtLastCheck;
+
+ if (timeDiff == 0)
+ timeDiff = 1;
+
+ m_timeExecuting += timeDiff;
+ m_timeAtLastCheck = currentTime;
+
+ // Adjust the tick threshold so we get the next checkTimeout call in the
+ // interval specified in intervalBetweenChecks.
+ m_ticksUntilNextCheck = static_cast<unsigned>((static_cast<float>(intervalBetweenChecks) / timeDiff) * m_ticksUntilNextCheck);
+ // If the new threshold is 0 reset it to the default threshold. This can happen if the timeDiff is higher than the
+ // preferred script check time interval.
+ if (m_ticksUntilNextCheck == 0)
+ m_ticksUntilNextCheck = ticksUntilFirstCheck;
+
+ if (m_timeoutInterval && m_timeExecuting > m_timeoutInterval) {
+ if (exec->dynamicGlobalObject()->globalObjectMethodTable()->shouldInterruptScript(exec->dynamicGlobalObject()))
+ return true;
+
+ reset();
+ }
+
+ return false;
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/TimeoutChecker.h b/Source/JavaScriptCore/runtime/TimeoutChecker.h
new file mode 100644
index 000000000..5925641f8
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/TimeoutChecker.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TimeoutChecker_h
+#define TimeoutChecker_h
+
+#include <wtf/Assertions.h>
+
+namespace JSC {
+
+ class ExecState;
+
+ class TimeoutChecker {
+ public:
+ TimeoutChecker();
+
+ void setTimeoutInterval(unsigned timeoutInterval) { m_timeoutInterval = timeoutInterval; }
+ unsigned timeoutInterval() const { return m_timeoutInterval; }
+
+ unsigned ticksUntilNextCheck() { return m_ticksUntilNextCheck; }
+
+ void start()
+ {
+ if (!m_startCount)
+ reset();
+ ++m_startCount;
+ }
+
+ void stop()
+ {
+ ASSERT(m_startCount);
+ --m_startCount;
+ }
+
+ void reset();
+
+ bool didTimeOut(ExecState*);
+
+ private:
+ unsigned m_timeoutInterval;
+ unsigned m_timeAtLastCheck;
+ unsigned m_timeExecuting;
+ unsigned m_startCount;
+ unsigned m_ticksUntilNextCheck;
+ };
+
+} // namespace JSC
+
+#endif // TimeoutChecker_h
diff --git a/Source/JavaScriptCore/runtime/Tracing.d b/Source/JavaScriptCore/runtime/Tracing.d
new file mode 100644
index 000000000..da854b990
--- /dev/null
+++ b/Source/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();
+
+ 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/Source/JavaScriptCore/runtime/Tracing.h b/Source/JavaScriptCore/runtime/Tracing.h
new file mode 100644
index 000000000..c28c85f61
--- /dev/null
+++ b/Source/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()
+#define JAVASCRIPTCORE_GC_END_ENABLED() 0
+
+#define JAVASCRIPTCORE_GC_MARKED()
+#define JAVASCRIPTCORE_GC_MARKED_ENABLED() 0
+
+#define JAVASCRIPTCORE_PROFILE_WILL_EXECUTE(arg0, arg1, arg2, arg3)
+#define JAVASCRIPTCORE_PROFILE_WILL_EXECUTE_ENABLED() 0
+
+#define JAVASCRIPTCORE_PROFILE_DID_EXECUTE(arg0, arg1, arg2, arg3)
+#define JAVASCRIPTCORE_PROFILE_DID_EXECUTE_ENABLED() 0
+
+#endif
+
+#endif // Tracing_h
diff --git a/Source/JavaScriptCore/runtime/UString.cpp b/Source/JavaScriptCore/runtime/UString.cpp
new file mode 100644
index 000000000..5b1e9a0e0
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/UString.cpp
@@ -0,0 +1,475 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "UString.h"
+
+#include "JSGlobalObjectFunctions.h"
+#include "Heap.h"
+#include "Identifier.h"
+#include "Operations.h"
+#include <ctype.h>
+#include <limits.h>
+#include <limits>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StringExtras.h>
+#include <wtf/Vector.h>
+#include <wtf/dtoa.h>
+#include <wtf/unicode/UTF8.h>
+
+#if HAVE(STRINGS_H)
+#include <strings.h>
+#endif
+
+using namespace WTF;
+using namespace WTF::Unicode;
+using namespace std;
+
+namespace JSC {
+
+COMPILE_ASSERT(sizeof(UString) == sizeof(void*), UString_should_stay_small);
+
+// Construct a string with UTF-16 data.
+UString::UString(const UChar* characters, unsigned length)
+ : m_impl(characters ? StringImpl::create(characters, length) : 0)
+{
+}
+
+// Construct a string with UTF-16 data, from a null-terminated source.
+UString::UString(const UChar* characters)
+{
+ if (!characters)
+ return;
+
+ int length = 0;
+ while (characters[length] != UChar(0))
+ ++length;
+
+ m_impl = StringImpl::create(characters, length);
+}
+
+// Construct a string with latin1 data.
+UString::UString(const LChar* characters, unsigned length)
+ : m_impl(characters ? StringImpl::create(characters, length) : 0)
+{
+}
+
+UString::UString(const char* characters, unsigned length)
+ : m_impl(characters ? StringImpl::create(reinterpret_cast<const LChar*>(characters), length) : 0)
+{
+}
+
+// Construct a string with latin1 data, from a null-terminated source.
+UString::UString(const LChar* characters)
+ : m_impl(characters ? StringImpl::create(characters) : 0)
+{
+}
+
+UString::UString(const char* characters)
+ : m_impl(characters ? StringImpl::create(reinterpret_cast<const LChar*>(characters)) : 0)
+{
+}
+
+UString UString::number(int i)
+{
+ LChar buf[1 + sizeof(i) * 3];
+ LChar* end = buf + WTF_ARRAY_LENGTH(buf);
+ LChar* p = end;
+
+ if (i == 0)
+ *--p = '0';
+ else if (i == INT_MIN) {
+ char minBuf[1 + sizeof(i) * 3];
+ snprintf(minBuf, sizeof(minBuf), "%d", INT_MIN);
+ return UString(minBuf);
+ } else {
+ bool negative = false;
+ if (i < 0) {
+ negative = true;
+ i = -i;
+ }
+ while (i) {
+ *--p = static_cast<unsigned short>((i % 10) + '0');
+ i /= 10;
+ }
+ if (negative)
+ *--p = '-';
+ }
+
+ return UString(p, static_cast<unsigned>(end - p));
+}
+
+UString UString::number(long long i)
+{
+ LChar buf[1 + sizeof(i) * 3];
+ LChar* end = buf + WTF_ARRAY_LENGTH(buf);
+ LChar* p = end;
+
+ if (i == 0)
+ *--p = '0';
+ else if (i == std::numeric_limits<long long>::min()) {
+ char minBuf[1 + sizeof(i) * 3];
+#if OS(WINDOWS)
+ snprintf(minBuf, sizeof(minBuf), "%I64d", std::numeric_limits<long long>::min());
+#else
+ snprintf(minBuf, sizeof(minBuf), "%lld", std::numeric_limits<long long>::min());
+#endif
+ return UString(minBuf);
+ } else {
+ bool negative = false;
+ if (i < 0) {
+ negative = true;
+ i = -i;
+ }
+ while (i) {
+ *--p = static_cast<unsigned short>((i % 10) + '0');
+ i /= 10;
+ }
+ if (negative)
+ *--p = '-';
+ }
+
+ return UString(p, static_cast<unsigned>(end - p));
+}
+
+UString UString::number(unsigned u)
+{
+ LChar buf[sizeof(u) * 3];
+ LChar* end = buf + WTF_ARRAY_LENGTH(buf);
+ LChar* p = end;
+
+ if (u == 0)
+ *--p = '0';
+ else {
+ while (u) {
+ *--p = static_cast<unsigned short>((u % 10) + '0');
+ u /= 10;
+ }
+ }
+
+ return UString(p, static_cast<unsigned>(end - p));
+}
+
+UString UString::number(long l)
+{
+ LChar buf[1 + sizeof(l) * 3];
+ LChar* end = buf + WTF_ARRAY_LENGTH(buf);
+ LChar* p = end;
+
+ if (l == 0)
+ *--p = '0';
+ else if (l == LONG_MIN) {
+ char minBuf[1 + sizeof(l) * 3];
+ snprintf(minBuf, sizeof(minBuf), "%ld", LONG_MIN);
+ return UString(minBuf);
+ } else {
+ bool negative = false;
+ if (l < 0) {
+ negative = true;
+ l = -l;
+ }
+ while (l) {
+ *--p = static_cast<unsigned short>((l % 10) + '0');
+ l /= 10;
+ }
+ if (negative)
+ *--p = '-';
+ }
+
+ return UString(p, end - p);
+}
+
+UString UString::number(double d)
+{
+ NumberToStringBuffer buffer;
+ return UString(numberToString(d, buffer));
+}
+
+UString UString::substringSharingImpl(unsigned offset, unsigned length) const
+{
+ // FIXME: We used to check against a limit of Heap::minExtraCost / sizeof(UChar).
+
+ unsigned stringLength = this->length();
+ offset = min(offset, stringLength);
+ length = min(length, stringLength - offset);
+
+ if (!offset && length == stringLength)
+ return *this;
+ return UString(StringImpl::create(m_impl, offset, length));
+}
+
+bool operator==(const UString& s1, const char *s2)
+{
+ if (s1.isEmpty())
+ return !s2;
+
+ return equal(s1.impl(), s2);
+}
+
+// This method assumes that all simple checks have been performed by
+// the inlined operator==() in the header file.
+bool equalSlowCase(const UString& s1, const UString& s2)
+{
+ StringImpl* rep1 = s1.impl();
+ StringImpl* rep2 = s2.impl();
+ unsigned size1 = rep1->length();
+
+ // At this point we know
+ // (a) that the strings are the same length and
+ // (b) that they are greater than zero length.
+ bool s1Is8Bit = rep1->is8Bit();
+ bool s2Is8Bit = rep2->is8Bit();
+
+ if (s1Is8Bit) {
+ const LChar* d1 = rep1->characters8();
+ if (s2Is8Bit) {
+ const LChar* d2 = rep2->characters8();
+
+ if (d1 == d2) // Check to see if the data pointers are the same.
+ return true;
+
+ // Do quick checks for sizes 1 and 2.
+ switch (size1) {
+ case 1:
+ return d1[0] == d2[0];
+ case 2:
+ return (d1[0] == d2[0]) & (d1[1] == d2[1]);
+ default:
+ return (!memcmp(d1, d2, size1 * sizeof(LChar)));
+ }
+ }
+
+ const UChar* d2 = rep2->characters16();
+
+ for (unsigned i = 0; i < size1; i++) {
+ if (d1[i] != d2[i])
+ return false;
+ }
+ return true;
+ }
+
+ if (s2Is8Bit) {
+ const UChar* d1 = rep1->characters16();
+ const LChar* d2 = rep2->characters8();
+
+ for (unsigned i = 0; i < size1; i++) {
+ if (d1[i] != d2[i])
+ return false;
+ }
+ return true;
+
+ }
+
+ const UChar* d1 = rep1->characters16();
+ const UChar* d2 = rep2->characters16();
+
+ if (d1 == d2) // Check to see if the data pointers are the same.
+ return true;
+
+ // Do quick checks for sizes 1 and 2.
+ switch (size1) {
+ case 1:
+ return d1[0] == d2[0];
+ case 2:
+ return (d1[0] == d2[0]) & (d1[1] == d2[1]);
+ default:
+ return (!memcmp(d1, d2, size1 * sizeof(UChar)));
+ }
+}
+
+bool operator<(const UString& s1, const UString& s2)
+{
+ const unsigned l1 = s1.length();
+ const unsigned l2 = s2.length();
+ const unsigned lmin = l1 < l2 ? l1 : l2;
+ if (s1.is8Bit() && s2.is8Bit()) {
+ const LChar* c1 = s1.characters8();
+ const LChar* c2 = s2.characters8();
+ unsigned length = 0;
+ while (length < lmin && *c1 == *c2) {
+ c1++;
+ c2++;
+ length++;
+ }
+ if (length < lmin)
+ return (c1[0] < c2[0]);
+
+ return (l1 < l2);
+ }
+ const UChar* c1 = s1.characters();
+ const UChar* c2 = s2.characters();
+ unsigned length = 0;
+ while (length < lmin && *c1 == *c2) {
+ c1++;
+ c2++;
+ length++;
+ }
+ if (length < lmin)
+ return (c1[0] < c2[0]);
+
+ return (l1 < l2);
+}
+
+bool operator>(const UString& s1, const UString& s2)
+{
+ const unsigned l1 = s1.length();
+ const unsigned l2 = s2.length();
+ const unsigned lmin = l1 < l2 ? l1 : l2;
+ const UChar* c1 = s1.characters();
+ const UChar* c2 = s2.characters();
+ unsigned l = 0;
+ while (l < lmin && *c1 == *c2) {
+ c1++;
+ c2++;
+ l++;
+ }
+ if (l < lmin)
+ return (c1[0] > c2[0]);
+
+ return (l1 > l2);
+}
+
+CString UString::ascii() const
+{
+ // Basic Latin1 (ISO) encoding - Unicode characters 0..255 are
+ // preserved, characters outside of this range are converted to '?'.
+
+ unsigned length = this->length();
+
+ if (this->is8Bit()) {
+ const LChar* characters = this->characters8();
+
+ char* characterBuffer;
+ CString result = CString::newUninitialized(length, characterBuffer);
+
+ for (unsigned i = 0; i < length; ++i) {
+ LChar ch = characters[i];
+ characterBuffer[i] = ch && (ch < 0x20 || ch > 0x7f) ? '?' : ch;
+ }
+
+ return result;
+ }
+
+ const UChar* characters = this->characters16();
+
+ char* characterBuffer;
+ CString result = CString::newUninitialized(length, characterBuffer);
+
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ characterBuffer[i] = ch && (ch < 0x20 || ch >= 0x7f) ? '?' : ch;
+ }
+
+ return result;
+}
+
+CString UString::latin1() const
+{
+ // Basic Latin1 (ISO) encoding - Unicode characters 0..255 are
+ // preserved, characters outside of this range are converted to '?'.
+
+ unsigned length = this->length();
+ const UChar* characters = this->characters();
+
+ char* characterBuffer;
+ CString result = CString::newUninitialized(length, characterBuffer);
+
+ for (unsigned i = 0; i < length; ++i) {
+ UChar ch = characters[i];
+ characterBuffer[i] = ch > 0xff ? '?' : ch;
+ }
+
+ return result;
+}
+
+// Helper to write a three-byte UTF-8 code point to the buffer, caller must check room is available.
+static inline void putUTF8Triple(char*& buffer, UChar ch)
+{
+ ASSERT(ch >= 0x0800);
+ *buffer++ = static_cast<char>(((ch >> 12) & 0x0F) | 0xE0);
+ *buffer++ = static_cast<char>(((ch >> 6) & 0x3F) | 0x80);
+ *buffer++ = static_cast<char>((ch & 0x3F) | 0x80);
+}
+
+CString UString::utf8(bool strict) const
+{
+ unsigned length = this->length();
+
+ if (!length)
+ return CString("", 0);
+
+ // Allocate a buffer big enough to hold all the characters
+ // (an individual UTF-16 UChar can only expand to 3 UTF-8 bytes).
+ // Optimization ideas, if we find this function is hot:
+ // * We could speculatively create a CStringBuffer to contain 'length'
+ // characters, and resize if necessary (i.e. if the buffer contains
+ // non-ascii characters). (Alternatively, scan the buffer first for
+ // ascii characters, so we know this will be sufficient).
+ // * We could allocate a CStringBuffer with an appropriate size to
+ // have a good chance of being able to write the string into the
+ // buffer without reallocing (say, 1.5 x length).
+ if (length > numeric_limits<unsigned>::max() / 3)
+ return CString();
+
+ Vector<char, 1024> bufferVector(length * 3);
+ char* buffer = bufferVector.data();
+
+ if (is8Bit()) {
+ const LChar* characters = this->characters8();
+
+ ConversionResult result = convertLatin1ToUTF8(&characters, characters + length, &buffer, buffer + bufferVector.size());
+ ASSERT_UNUSED(result, result != targetExhausted); // (length * 3) should be sufficient for any conversion
+ } else {
+ const UChar* characters = this->characters16();
+
+ ConversionResult result = convertUTF16ToUTF8(&characters, characters + length, &buffer, buffer + bufferVector.size(), strict);
+ ASSERT(result != targetExhausted); // (length * 3) should be sufficient for any conversion
+
+ // Only produced from strict conversion.
+ if (result == sourceIllegal)
+ return CString();
+
+ // Check for an unconverted high surrogate.
+ if (result == sourceExhausted) {
+ if (strict)
+ return CString();
+ // This should be one unpaired high surrogate. Treat it the same
+ // was as an unpaired high surrogate would have been handled in
+ // the middle of a string with non-strict conversion - which is
+ // to say, simply encode it to UTF-8.
+ ASSERT((characters + 1) == (this->characters() + length));
+ ASSERT((*characters >= 0xD800) && (*characters <= 0xDBFF));
+ // There should be room left, since one UChar hasn't been converted.
+ ASSERT((buffer + 3) <= (buffer + bufferVector.size()));
+ putUTF8Triple(buffer, *characters);
+ }
+ }
+
+ return CString(bufferVector.data(), buffer - bufferVector.data());
+}
+
+} // namespace JSC
diff --git a/Source/JavaScriptCore/runtime/UString.h b/Source/JavaScriptCore/runtime/UString.h
new file mode 100644
index 000000000..c05ae5081
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/UString.h
@@ -0,0 +1,288 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved.
+ * Copyright (C) 2009 Google Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef UString_h
+#define UString_h
+
+#include <wtf/text/StringImpl.h>
+
+namespace JSC {
+
+class UString {
+public:
+ // Construct a null string, distinguishable from an empty string.
+ UString() { }
+
+ // Construct a string with UTF-16 data.
+ UString(const UChar* characters, unsigned length);
+
+ // Construct a string with UTF-16 data, from a null-terminated source.
+ UString(const UChar*);
+
+ // Construct a string with latin1 data.
+ UString(const LChar* characters, unsigned length);
+ UString(const char* characters, unsigned length);
+
+ // Construct a string with latin1 data, from a null-terminated source.
+ UString(const LChar* characters);
+ UString(const char* characters);
+
+ // Construct a string referencing an existing StringImpl.
+ UString(StringImpl* impl) : m_impl(impl) { }
+ UString(PassRefPtr<StringImpl> impl) : m_impl(impl) { }
+ UString(RefPtr<StringImpl> impl) : m_impl(impl) { }
+
+ // Inline the destructor.
+ ALWAYS_INLINE ~UString() { }
+
+ void swap(UString& o) { m_impl.swap(o.m_impl); }
+
+ template<typename CharType, size_t inlineCapacity>
+ static UString adopt(Vector<CharType, inlineCapacity>& vector) { return StringImpl::adopt(vector); }
+
+ bool isNull() const { return !m_impl; }
+ bool isEmpty() const { return !m_impl || !m_impl->length(); }
+
+ StringImpl* impl() const { return m_impl.get(); }
+
+ unsigned length() const
+ {
+ if (!m_impl)
+ return 0;
+ return m_impl->length();
+ }
+
+ const UChar* characters() const
+ {
+ if (!m_impl)
+ return 0;
+ return m_impl->characters();
+ }
+
+ const LChar* characters8() const
+ {
+ if (!m_impl)
+ return 0;
+ ASSERT(m_impl->is8Bit());
+ return m_impl->characters8();
+ }
+
+ const UChar* characters16() const
+ {
+ if (!m_impl)
+ return 0;
+ ASSERT(!m_impl->is8Bit());
+ return m_impl->characters16();
+ }
+
+ template <typename CharType>
+ inline const CharType* getCharacters() const;
+
+ bool is8Bit() const { return m_impl->is8Bit(); }
+
+ CString ascii() const;
+ CString latin1() const;
+ CString utf8(bool strict = false) const;
+
+ UChar operator[](unsigned index) const
+ {
+ if (!m_impl || index >= m_impl->length())
+ return 0;
+ if (is8Bit())
+ return m_impl->characters8()[index];
+ return m_impl->characters16()[index];
+ }
+
+ static UString number(int);
+ static UString number(unsigned);
+ static UString number(long);
+ static UString number(long long);
+ static UString number(double);
+
+ // Find a single character or string, also with match function & latin1 forms.
+ size_t find(UChar c, unsigned start = 0) const
+ { return m_impl ? m_impl->find(c, start) : notFound; }
+ size_t find(const UString& str, unsigned start = 0) const
+ { return m_impl ? m_impl->find(str.impl(), start) : notFound; }
+ size_t find(const LChar* str, unsigned start = 0) const
+ { return m_impl ? m_impl->find(str, start) : notFound; }
+
+ // Find the last instance of a single character or string.
+ size_t reverseFind(UChar c, unsigned start = UINT_MAX) const
+ { return m_impl ? m_impl->reverseFind(c, start) : notFound; }
+ size_t reverseFind(const UString& str, unsigned start = UINT_MAX) const
+ { return m_impl ? m_impl->reverseFind(str.impl(), start) : notFound; }
+
+ UString substringSharingImpl(unsigned pos, unsigned len = UINT_MAX) const;
+
+private:
+ RefPtr<StringImpl> m_impl;
+};
+
+template<>
+inline const LChar* UString::getCharacters<LChar>() const
+{
+ ASSERT(is8Bit());
+ return characters8();
+}
+
+template<>
+inline const UChar* UString::getCharacters<UChar>() const
+{
+ ASSERT(!is8Bit());
+ return characters16();
+}
+
+NEVER_INLINE bool equalSlowCase(const UString& s1, const UString& s2);
+
+ALWAYS_INLINE bool operator==(const UString& s1, const UString& s2)
+{
+ StringImpl* rep1 = s1.impl();
+ StringImpl* rep2 = s2.impl();
+
+ if (rep1 == rep2) // If they're the same rep, they're equal.
+ return true;
+
+ unsigned size1 = 0;
+ unsigned size2 = 0;
+
+ if (rep1)
+ size1 = rep1->length();
+
+ if (rep2)
+ size2 = rep2->length();
+
+ if (size1 != size2) // If the lengths are not the same, we're done.
+ return false;
+
+ if (!size1)
+ return true;
+
+ if (size1 == 1)
+ return (*rep1)[0u] == (*rep2)[0u];
+
+ return equalSlowCase(s1, s2);
+}
+
+
+inline bool operator!=(const UString& s1, const UString& s2)
+{
+ return !JSC::operator==(s1, s2);
+}
+
+bool operator<(const UString& s1, const UString& s2);
+bool operator>(const UString& s1, const UString& s2);
+
+bool operator==(const UString& s1, const char* s2);
+
+inline bool operator!=(const UString& s1, const char* s2)
+{
+ return !JSC::operator==(s1, s2);
+}
+
+inline bool operator==(const char *s1, const UString& s2)
+{
+ return operator==(s2, s1);
+}
+
+inline bool operator!=(const char *s1, const UString& s2)
+{
+ return !JSC::operator==(s1, s2);
+}
+
+inline int codePointCompare(const UString& s1, const UString& s2)
+{
+ return codePointCompare(s1.impl(), s2.impl());
+}
+
+struct UStringHash {
+ static unsigned hash(StringImpl* key) { return key->hash(); }
+ static bool equal(const StringImpl* a, const StringImpl* b)
+ {
+ if (a == b)
+ return true;
+ if (!a || !b)
+ return false;
+
+ unsigned aLength = a->length();
+ unsigned bLength = b->length();
+ if (aLength != bLength)
+ return false;
+
+ // FIXME: perhaps we should have a more abstract macro that indicates when
+ // going 4 bytes at a time is unsafe
+#if CPU(ARM) || CPU(SH4) || CPU(MIPS) || CPU(SPARC)
+ const UChar* aChars = a->characters();
+ const UChar* bChars = b->characters();
+ for (unsigned i = 0; i != aLength; ++i) {
+ if (*aChars++ != *bChars++)
+ return false;
+ }
+ return true;
+#else
+ /* Do it 4-bytes-at-a-time on architectures where it's safe */
+ const uint32_t* aChars = reinterpret_cast<const uint32_t*>(a->characters());
+ const uint32_t* bChars = reinterpret_cast<const uint32_t*>(b->characters());
+
+ unsigned halfLength = aLength >> 1;
+ for (unsigned i = 0; i != halfLength; ++i)
+ if (*aChars++ != *bChars++)
+ return false;
+
+ if (aLength & 1 && *reinterpret_cast<const uint16_t*>(aChars) != *reinterpret_cast<const uint16_t*>(bChars))
+ return false;
+
+ return true;
+#endif
+ }
+
+ static unsigned hash(const RefPtr<StringImpl>& key) { return key->hash(); }
+ static bool equal(const RefPtr<StringImpl>& a, const RefPtr<StringImpl>& b)
+ {
+ return equal(a.get(), b.get());
+ }
+
+ static unsigned hash(const UString& key) { return key.impl()->hash(); }
+ static bool equal(const UString& a, const UString& b)
+ {
+ return equal(a.impl(), b.impl());
+ }
+
+ static const bool safeToCompareToEmptyOrDeleted = false;
+};
+
+} // namespace JSC
+
+namespace WTF {
+
+// UStringHash is the default hash for UString
+template<typename T> struct DefaultHash;
+template<> struct DefaultHash<JSC::UString> {
+ typedef JSC::UStringHash Hash;
+};
+
+template <> struct VectorTraits<JSC::UString> : SimpleClassVectorTraits { };
+
+} // namespace WTF
+
+#endif
+
diff --git a/Source/JavaScriptCore/runtime/UStringBuilder.h b/Source/JavaScriptCore/runtime/UStringBuilder.h
new file mode 100644
index 000000000..31ccf382a
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/UStringBuilder.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef UStringBuilder_h
+#define UStringBuilder_h
+
+#include <wtf/text/StringBuilder.h>
+
+namespace JSC {
+
+class UStringBuilder : public StringBuilder {
+public:
+ using StringBuilder::append;
+ void append(const UString& str) { append(String(str.impl())); }
+
+ UString toUString() { return toString().impl(); }
+};
+
+} // namespace JSC
+
+#endif // UStringBuilder_h
diff --git a/Source/JavaScriptCore/runtime/UStringConcatenate.h b/Source/JavaScriptCore/runtime/UStringConcatenate.h
new file mode 100644
index 000000000..cbd4e60ca
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/UStringConcatenate.h
@@ -0,0 +1,141 @@
+/*
+ * Copyright (C) 2010 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED 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 UStringConcatenate_h
+#define UStringConcatenate_h
+
+#include "UString.h"
+#include <wtf/text/StringConcatenate.h>
+
+namespace WTF {
+
+template<>
+class StringTypeAdapter<JSC::UString> {
+public:
+ StringTypeAdapter<JSC::UString>(JSC::UString& string)
+ : m_string(string)
+ , m_length(string.length())
+ {
+ }
+
+ unsigned length() { return m_length; }
+
+ bool is8Bit() { return m_string.isNull() || m_string.is8Bit(); }
+
+ void writeTo(LChar* destination)
+ {
+ const LChar* characters = m_string.characters8();
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = characters[i];
+ }
+
+ void writeTo(UChar* destination)
+ {
+ if (is8Bit()) {
+ const LChar* characters = m_string.characters8();
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = characters[i];
+ } else {
+ const UChar* characters = m_string.characters16();
+ for (unsigned i = 0; i < m_length; ++i)
+ destination[i] = characters[i];
+ }
+ }
+
+private:
+ const JSC::UString& m_string;
+ unsigned m_length;
+};
+
+}; // namespace WTF
+
+namespace JSC {
+
+template<typename StringType1, typename StringType2>
+UString makeUString(StringType1 string1, StringType2 string2)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4, string5);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4, string5, string6);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4, string5, string6, string7);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+template<typename StringType1, typename StringType2, typename StringType3, typename StringType4, typename StringType5, typename StringType6, typename StringType7, typename StringType8>
+UString makeUString(StringType1 string1, StringType2 string2, StringType3 string3, StringType4 string4, StringType5 string5, StringType6 string6, StringType7 string7, StringType8 string8)
+{
+ PassRefPtr<StringImpl> resultImpl = WTF::tryMakeString(string1, string2, string3, string4, string5, string6, string7, string8);
+ if (!resultImpl)
+ CRASH();
+ return resultImpl;
+}
+
+} // namespace JSC
+
+#endif
diff --git a/Source/JavaScriptCore/runtime/Uint16WithFraction.h b/Source/JavaScriptCore/runtime/Uint16WithFraction.h
new file mode 100644
index 000000000..0e5c5f91c
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/Uint16WithFraction.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef Uint16WithFraction_h
+#define Uint16WithFraction_h
+
+#include <wtf/MathExtras.h>
+
+namespace JSC {
+
+// Would be nice if this was a static const member, but the OS X linker
+// seems to want a symbol in the binary in that case...
+#define oneGreaterThanMaxUInt16 0x10000
+
+// A uint16_t with an infinite precision fraction. Upon overflowing
+// the uint16_t range, this class will clamp to oneGreaterThanMaxUInt16.
+// This is used in converting the fraction part of a number to a string.
+class Uint16WithFraction {
+public:
+ explicit Uint16WithFraction(double number, uint16_t divideByExponent = 0)
+ {
+ ASSERT(number && isfinite(number) && !signbit(number));
+
+ // Check for values out of uint16_t range.
+ if (number >= oneGreaterThanMaxUInt16) {
+ m_values.append(oneGreaterThanMaxUInt16);
+ m_leadingZeros = 0;
+ return;
+ }
+
+ // Append the units to m_values.
+ double integerPart = floor(number);
+ m_values.append(static_cast<uint32_t>(integerPart));
+
+ bool sign;
+ int32_t exponent;
+ uint64_t mantissa;
+ decomposeDouble(number - integerPart, sign, exponent, mantissa);
+ ASSERT(!sign && exponent < 0);
+ exponent -= divideByExponent;
+
+ int32_t zeroBits = -exponent;
+ --zeroBits;
+
+ // Append the append words for to m_values.
+ while (zeroBits >= 32) {
+ m_values.append(0);
+ zeroBits -= 32;
+ }
+
+ // Left align the 53 bits of the mantissa within 96 bits.
+ uint32_t values[3];
+ values[0] = static_cast<uint32_t>(mantissa >> 21);
+ values[1] = static_cast<uint32_t>(mantissa << 11);
+ values[2] = 0;
+ // Shift based on the remainder of the exponent.
+ if (zeroBits) {
+ values[2] = values[1] << (32 - zeroBits);
+ values[1] = (values[1] >> zeroBits) | (values[0] << (32 - zeroBits));
+ values[0] = (values[0] >> zeroBits);
+ }
+ m_values.append(values[0]);
+ m_values.append(values[1]);
+ m_values.append(values[2]);
+
+ // Canonicalize; remove any trailing zeros.
+ while (m_values.size() > 1 && !m_values.last())
+ m_values.removeLast();
+
+ // Count the number of leading zero, this is useful in optimizing multiplies.
+ m_leadingZeros = 0;
+ while (m_leadingZeros < m_values.size() && !m_values[m_leadingZeros])
+ ++m_leadingZeros;
+ }
+
+ Uint16WithFraction& operator*=(uint16_t multiplier)
+ {
+ ASSERT(checkConsistency());
+
+ // iteratate backwards over the fraction until we reach the leading zeros,
+ // passing the carry from one calculation into the next.
+ uint64_t accumulator = 0;
+ for (size_t i = m_values.size(); i > m_leadingZeros; ) {
+ --i;
+ accumulator += static_cast<uint64_t>(m_values[i]) * static_cast<uint64_t>(multiplier);
+ m_values[i] = static_cast<uint32_t>(accumulator);
+ accumulator >>= 32;
+ }
+
+ if (!m_leadingZeros) {
+ // With a multiplicand and multiplier in the uint16_t range, this cannot carry
+ // (even allowing for the infinity value).
+ ASSERT(!accumulator);
+ // Check for overflow & clamp to 'infinity'.
+ if (m_values[0] >= oneGreaterThanMaxUInt16) {
+ m_values.shrink(1);
+ m_values[0] = oneGreaterThanMaxUInt16;
+ m_leadingZeros = 0;
+ return *this;
+ }
+ } else if (accumulator) {
+ // Check for carry from the last multiply, if so overwrite last leading zero.
+ m_values[--m_leadingZeros] = static_cast<uint32_t>(accumulator);
+ // The limited range of the multiplier should mean that even if we carry into
+ // the units, we don't need to check for overflow of the uint16_t range.
+ ASSERT(m_values[0] < oneGreaterThanMaxUInt16);
+ }
+
+ // Multiplication by an even value may introduce trailing zeros; if so, clean them
+ // up. (Keeping the value in a normalized form makes some of the comparison operations
+ // more efficient).
+ while (m_values.size() > 1 && !m_values.last())
+ m_values.removeLast();
+ ASSERT(checkConsistency());
+ return *this;
+ }
+
+ bool operator<(const Uint16WithFraction& other)
+ {
+ ASSERT(checkConsistency());
+ ASSERT(other.checkConsistency());
+
+ // Iterate over the common lengths of arrays.
+ size_t minSize = std::min(m_values.size(), other.m_values.size());
+ for (size_t index = 0; index < minSize; ++index) {
+ // If we find a value that is not equal, compare and return.
+ uint32_t fromThis = m_values[index];
+ uint32_t fromOther = other.m_values[index];
+ if (fromThis != fromOther)
+ return fromThis < fromOther;
+ }
+ // If these numbers have the same lengths, they are equal,
+ // otherwise which ever number has a longer fraction in larger.
+ return other.m_values.size() > minSize;
+ }
+
+ // Return the floor (non-fractional portion) of the number, clearing this to zero,
+ // leaving the fractional part unchanged.
+ uint32_t floorAndSubtract()
+ {
+ // 'floor' is simple the integer portion of the value.
+ uint32_t floor = m_values[0];
+
+ // If floor is non-zero,
+ if (floor) {
+ m_values[0] = 0;
+ m_leadingZeros = 1;
+ while (m_leadingZeros < m_values.size() && !m_values[m_leadingZeros])
+ ++m_leadingZeros;
+ }
+
+ return floor;
+ }
+
+ // Compare this value to 0.5, returns -1 for less than, 0 for equal, 1 for greater.
+ int comparePoint5()
+ {
+ ASSERT(checkConsistency());
+ // If units != 0, this is greater than 0.5.
+ if (m_values[0])
+ return 1;
+ // If size == 1 this value is 0, hence < 0.5.
+ if (m_values.size() == 1)
+ return -1;
+ // Compare to 0.5.
+ if (m_values[1] > 0x80000000ul)
+ return 1;
+ if (m_values[1] < 0x80000000ul)
+ return -1;
+ // Check for more words - since normalized numbers have no trailing zeros, if
+ // there are more that two digits we can assume at least one more is non-zero,
+ // and hence the value is > 0.5.
+ return m_values.size() > 2 ? 1 : 0;
+ }
+
+ // Return true if the sum of this plus addend would be greater than 1.
+ bool sumGreaterThanOne(const Uint16WithFraction& addend)
+ {
+ ASSERT(checkConsistency());
+ ASSERT(addend.checkConsistency());
+
+ // First, sum the units. If the result is greater than one, return true.
+ // If equal to one, return true if either number has a fractional part.
+ uint32_t sum = m_values[0] + addend.m_values[0];
+ if (sum)
+ return sum > 1 || std::max(m_values.size(), addend.m_values.size()) > 1;
+
+ // We could still produce a result greater than zero if addition of the next
+ // word from the fraction were to carry, leaving a result > 0.
+
+ // Iterate over the common lengths of arrays.
+ size_t minSize = std::min(m_values.size(), addend.m_values.size());
+ for (size_t index = 1; index < minSize; ++index) {
+ // Sum the next word from this & the addend.
+ uint32_t fromThis = m_values[index];
+ uint32_t fromAddend = addend.m_values[index];
+ sum = fromThis + fromAddend;
+
+ // Check for overflow. If so, check whether the remaining result is non-zero,
+ // or if there are any further words in the fraction.
+ if (sum < fromThis)
+ return sum || (index + 1) < std::max(m_values.size(), addend.m_values.size());
+
+ // If the sum is uint32_t max, then we would carry a 1 if addition of the next
+ // digits in the number were to overflow.
+ if (sum != 0xFFFFFFFF)
+ return false;
+ }
+ return false;
+ }
+
+private:
+ bool checkConsistency() const
+ {
+ // All values should have at least one value.
+ return (m_values.size())
+ // The units value must be a uint16_t, or the value is the overflow value.
+ && (m_values[0] < oneGreaterThanMaxUInt16 || (m_values[0] == oneGreaterThanMaxUInt16 && m_values.size() == 1))
+ // There should be no trailing zeros (unless this value is zero!).
+ && (m_values.last() || m_values.size() == 1);
+ }
+
+ // The internal storage of the number. This vector is always at least one entry in size,
+ // with the first entry holding the portion of the number greater than zero. The first
+ // value always hold a value in the uint16_t range, or holds the value oneGreaterThanMaxUInt16 to
+ // indicate the value has overflowed to >= 0x10000. If the units value is oneGreaterThanMaxUInt16,
+ // there can be no fraction (size must be 1).
+ //
+ // Subsequent values in the array represent portions of the fractional part of this number.
+ // The total value of the number is the sum of (m_values[i] / pow(2^32, i)), for each i
+ // in the array. The vector should contain no trailing zeros, except for the value '0',
+ // represented by a vector contianing a single zero value. These constraints are checked
+ // by 'checkConsistency()', above.
+ //
+ // The inline capacity of the vector is set to be able to contain any IEEE double (1 for
+ // the units column, 32 for zeros introduced due to an exponent up to -3FE, and 2 for
+ // bits taken from the mantissa).
+ Vector<uint32_t, 36> m_values;
+
+ // Cache a count of the number of leading zeros in m_values. We can use this to optimize
+ // methods that would otherwise need visit all words in the vector, e.g. multiplication.
+ size_t m_leadingZeros;
+};
+
+}
+
+#endif
+
diff --git a/Source/JavaScriptCore/runtime/WeakGCMap.h b/Source/JavaScriptCore/runtime/WeakGCMap.h
new file mode 100644
index 000000000..1bb3cd5bb
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WeakGCMap.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WeakGCMap_h
+#define WeakGCMap_h
+
+#include "Handle.h"
+#include "JSGlobalData.h"
+#include <wtf/HashMap.h>
+
+namespace JSC {
+
+// A HashMap for GC'd values that removes entries when the associated value
+// dies.
+template <typename KeyType, typename MappedType> struct DefaultWeakGCMapFinalizerCallback {
+ static void* finalizerContextFor(KeyType key)
+ {
+ return reinterpret_cast<void*>(key);
+ }
+
+ static KeyType keyForFinalizer(void* context, typename HandleTypes<MappedType>::ExternalType)
+ {
+ return reinterpret_cast<KeyType>(context);
+ }
+};
+
+template<typename KeyType, typename MappedType, typename FinalizerCallback = DefaultWeakGCMapFinalizerCallback<KeyType, MappedType>, typename HashArg = typename DefaultHash<KeyType>::Hash, typename KeyTraitsArg = HashTraits<KeyType> >
+class WeakGCMap : private WeakHandleOwner {
+ WTF_MAKE_FAST_ALLOCATED;
+ WTF_MAKE_NONCOPYABLE(WeakGCMap);
+
+ typedef HashMap<KeyType, HandleSlot, HashArg, KeyTraitsArg> MapType;
+ typedef typename HandleTypes<MappedType>::ExternalType ExternalType;
+ typedef typename MapType::iterator map_iterator;
+
+public:
+
+ struct iterator {
+ friend class WeakGCMap;
+ iterator(map_iterator iter)
+ : m_iterator(iter)
+ {
+ }
+
+ std::pair<KeyType, ExternalType> get() const { return std::make_pair(m_iterator->first, HandleTypes<MappedType>::getFromSlot(m_iterator->second)); }
+ std::pair<KeyType, HandleSlot> getSlot() const { return *m_iterator; }
+
+ iterator& operator++() { ++m_iterator; return *this; }
+
+ // postfix ++ intentionally omitted
+
+ // Comparison.
+ bool operator==(const iterator& other) const { return m_iterator == other.m_iterator; }
+ bool operator!=(const iterator& other) const { return m_iterator != other.m_iterator; }
+
+ private:
+ map_iterator m_iterator;
+ };
+
+ WeakGCMap()
+ {
+ }
+
+ bool isEmpty() { return m_map.isEmpty(); }
+ void clear()
+ {
+ map_iterator end = m_map.end();
+ for (map_iterator ptr = m_map.begin(); ptr != end; ++ptr)
+ HandleHeap::heapFor(ptr->second)->deallocate(ptr->second);
+ m_map.clear();
+ }
+
+ bool contains(const KeyType& key) const
+ {
+ return m_map.contains(key);
+ }
+
+ iterator find(const KeyType& key)
+ {
+ return m_map.find(key);
+ }
+
+ void remove(iterator iter)
+ {
+ ASSERT(iter.m_iterator != m_map.end());
+ HandleSlot slot = iter.m_iterator->second;
+ ASSERT(slot);
+ HandleHeap::heapFor(slot)->deallocate(slot);
+ m_map.remove(iter.m_iterator);
+ }
+
+ ExternalType get(const KeyType& key) const
+ {
+ return HandleTypes<MappedType>::getFromSlot(m_map.get(key));
+ }
+
+ HandleSlot getSlot(const KeyType& key) const
+ {
+ return m_map.get(key);
+ }
+
+ pair<iterator, bool> add(JSGlobalData& globalData, const KeyType& key, ExternalType value)
+ {
+ pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
+ if (iter.second) {
+ HandleSlot slot = globalData.heap.handleHeap()->allocate();
+ iter.first->second = slot;
+ HandleHeap::heapFor(slot)->makeWeak(slot, this, FinalizerCallback::finalizerContextFor(key));
+ HandleHeap::heapFor(slot)->writeBarrier(slot, value);
+ *slot = value;
+ }
+ return iter;
+ }
+
+ void set(iterator iter, ExternalType value)
+ {
+ HandleSlot slot = iter.m_iterator->second;
+ ASSERT(slot);
+ HandleHeap::heapFor(slot)->writeBarrier(slot, value);
+ *slot = value;
+ }
+
+ void set(JSGlobalData& globalData, const KeyType& key, ExternalType value)
+ {
+ pair<typename MapType::iterator, bool> iter = m_map.add(key, 0);
+ HandleSlot slot = iter.first->second;
+ if (iter.second) {
+ slot = globalData.heap.handleHeap()->allocate();
+ HandleHeap::heapFor(slot)->makeWeak(slot, this, key);
+ iter.first->second = slot;
+ }
+ HandleHeap::heapFor(slot)->writeBarrier(slot, value);
+ *slot = value;
+ }
+
+ ExternalType take(const KeyType& key)
+ {
+ HandleSlot slot = m_map.take(key);
+ if (!slot)
+ return HashTraits<ExternalType>::emptyValue();
+ ExternalType result = HandleTypes<MappedType>::getFromSlot(slot);
+ HandleHeap::heapFor(slot)->deallocate(slot);
+ return result;
+ }
+
+ size_t size() { return m_map.size(); }
+
+ iterator begin() { return iterator(m_map.begin()); }
+ iterator end() { return iterator(m_map.end()); }
+
+ ~WeakGCMap()
+ {
+ clear();
+ }
+
+private:
+ virtual void finalize(Handle<Unknown> handle, void* context)
+ {
+ HandleSlot slot = m_map.take(FinalizerCallback::keyForFinalizer(context, HandleTypes<MappedType>::getFromSlot(handle.slot())));
+ ASSERT(slot);
+ HandleHeap::heapFor(slot)->deallocate(slot);
+ }
+
+ MapType m_map;
+};
+
+} // namespace JSC
+
+#endif // WeakGCMap_h
diff --git a/Source/JavaScriptCore/runtime/WeakRandom.h b/Source/JavaScriptCore/runtime/WeakRandom.h
new file mode 100644
index 000000000..6083980d2
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WeakRandom.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2009 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ *
+ * Copyright (c) 2009 Ian C. Bullard
+ *
+ * Permission is hereby granted, free of charge, to any person
+ * obtaining a copy of this software and associated documentation
+ * files (the "Software"), to deal in the Software without
+ * restriction, including without limitation the rights to use,
+ * copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the
+ * Software is furnished to do so, subject to the following
+ * conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
+ * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
+ * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+ * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
+ * OTHER DEALINGS IN THE SOFTWARE.
+ */
+
+#ifndef WeakRandom_h
+#define WeakRandom_h
+
+#include <limits.h>
+#include <wtf/StdLibExtras.h>
+
+namespace JSC {
+
+class WeakRandom {
+public:
+ WeakRandom(unsigned seed)
+ : m_low(seed ^ 0x49616E42)
+ , m_high(seed)
+ {
+ }
+
+ double get()
+ {
+ return advance() / (UINT_MAX + 1.0);
+ }
+
+ unsigned getUint32()
+ {
+ return advance();
+ }
+
+private:
+ unsigned advance()
+ {
+ m_high = (m_high << 16) + (m_high >> 16);
+ m_high += m_low;
+ m_low += m_high;
+ return m_high;
+ }
+
+ unsigned m_low;
+ unsigned m_high;
+};
+
+} // namespace JSC
+
+#endif // WeakRandom_h
diff --git a/Source/JavaScriptCore/runtime/WriteBarrier.h b/Source/JavaScriptCore/runtime/WriteBarrier.h
new file mode 100644
index 000000000..525fc0926
--- /dev/null
+++ b/Source/JavaScriptCore/runtime/WriteBarrier.h
@@ -0,0 +1,231 @@
+/*
+ * Copyright (C) 2011 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
+ * THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef WriteBarrier_h
+#define WriteBarrier_h
+
+#include "HandleTypes.h"
+#include "Heap.h"
+#include "SamplingCounter.h"
+#include "TypeTraits.h"
+
+namespace JSC {
+
+class JSCell;
+class JSGlobalData;
+class JSGlobalObject;
+
+template<class T> class WriteBarrierBase;
+template<> class WriteBarrierBase<JSValue>;
+
+void slowValidateCell(JSCell*);
+void slowValidateCell(JSGlobalObject*);
+
+#if ENABLE(GC_VALIDATION)
+template<class T> inline void validateCell(T cell)
+{
+ ASSERT_GC_OBJECT_INHERITS(cell, &WTF::RemovePointer<T>::Type::s_info);
+}
+
+template<> inline void validateCell<JSCell*>(JSCell* cell)
+{
+ slowValidateCell(cell);
+}
+
+template<> inline void validateCell<JSGlobalObject*>(JSGlobalObject* globalObject)
+{
+ slowValidateCell(globalObject);
+}
+#else
+template<class T> inline void validateCell(T)
+{
+}
+#endif
+
+// We have a separate base class with no constructors for use in Unions.
+template <typename T> class WriteBarrierBase {
+public:
+ void set(JSGlobalData& globalData, const JSCell* owner, T* value)
+ {
+ ASSERT(value);
+ validateCell(value);
+ setEarlyValue(globalData, owner, value);
+ }
+
+ void setMayBeNull(JSGlobalData& globalData, const JSCell* owner, T* value)
+ {
+ if (value)
+ validateCell(value);
+ setEarlyValue(globalData, owner, value);
+ }
+
+ // Should only be used by JSCell during early initialisation
+ // when some basic types aren't yet completely instantiated
+ void setEarlyValue(JSGlobalData&, const JSCell* owner, T* value)
+ {
+ this->m_cell = reinterpret_cast<JSCell*>(value);
+ Heap::writeBarrier(owner, this->m_cell);
+ }
+
+ T* get() const
+ {
+ if (m_cell)
+ validateCell(m_cell);
+ return reinterpret_cast<T*>(m_cell);
+ }
+
+ T* operator*() const
+ {
+ ASSERT(m_cell);
+ validateCell<T>(static_cast<T*>(m_cell));
+ return static_cast<T*>(m_cell);
+ }
+
+ T* operator->() const
+ {
+ ASSERT(m_cell);
+ validateCell(static_cast<T*>(m_cell));
+ return static_cast<T*>(m_cell);
+ }
+
+ void clear() { m_cell = 0; }
+
+ JSCell** slot() { return &m_cell; }
+
+ typedef T* (WriteBarrierBase::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType*() const { return m_cell ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
+
+ bool operator!() const { return !m_cell; }
+
+ void setWithoutWriteBarrier(T* value)
+ {
+#if ENABLE(WRITE_BARRIER_PROFILING)
+ WriteBarrierCounters::usesWithoutBarrierFromCpp.count();
+#endif
+ this->m_cell = reinterpret_cast<JSCell*>(value);
+ }
+
+#if ENABLE(GC_VALIDATION)
+ T* unvalidatedGet() const { return reinterpret_cast<T*>(m_cell); }
+#endif
+
+private:
+ JSCell* m_cell;
+};
+
+template <> class WriteBarrierBase<Unknown> {
+public:
+ void set(JSGlobalData&, const JSCell* owner, JSValue value)
+ {
+ m_value = JSValue::encode(value);
+ Heap::writeBarrier(owner, value);
+ }
+
+ void setWithoutWriteBarrier(JSValue value)
+ {
+ m_value = JSValue::encode(value);
+ }
+
+ JSValue get() const
+ {
+ return JSValue::decode(m_value);
+ }
+ void clear() { m_value = JSValue::encode(JSValue()); }
+ void setUndefined() { m_value = JSValue::encode(jsUndefined()); }
+ bool isNumber() const { return get().isNumber(); }
+ bool isObject() const { return get().isObject(); }
+ bool isNull() const { return get().isNull(); }
+ bool isGetterSetter() const { return get().isGetterSetter(); }
+
+ JSValue* slot()
+ {
+ union {
+ EncodedJSValue* v;
+ JSValue* slot;
+ } u;
+ u.v = &m_value;
+ return u.slot;
+ }
+
+ typedef JSValue (WriteBarrierBase::*UnspecifiedBoolType);
+ operator UnspecifiedBoolType*() const { return get() ? reinterpret_cast<UnspecifiedBoolType*>(1) : 0; }
+ bool operator!() const { return !get(); }
+
+private:
+ EncodedJSValue m_value;
+};
+
+template <typename T> class WriteBarrier : public WriteBarrierBase<T> {
+public:
+ WriteBarrier()
+ {
+ this->setWithoutWriteBarrier(0);
+ }
+
+ WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value)
+ {
+ this->set(globalData, owner, value);
+ }
+
+ enum MayBeNullTag { MayBeNull };
+ WriteBarrier(JSGlobalData& globalData, const JSCell* owner, T* value, MayBeNullTag)
+ {
+ this->setMayBeNull(globalData, owner, value);
+ }
+};
+
+template <> class WriteBarrier<Unknown> : public WriteBarrierBase<Unknown> {
+public:
+ WriteBarrier()
+ {
+ this->setWithoutWriteBarrier(JSValue());
+ }
+
+ WriteBarrier(JSGlobalData& globalData, const JSCell* owner, JSValue value)
+ {
+ this->set(globalData, owner, value);
+ }
+};
+
+template <typename U, typename V> inline bool operator==(const WriteBarrierBase<U>& lhs, const WriteBarrierBase<V>& rhs)
+{
+ return lhs.get() == rhs.get();
+}
+
+// MarkStack functions
+
+template<typename T> inline void MarkStack::append(WriteBarrierBase<T>* slot)
+{
+ internalAppend(*slot->slot());
+}
+
+ALWAYS_INLINE void MarkStack::appendValues(WriteBarrierBase<Unknown>* barriers, size_t count)
+{
+ append(barriers->slot(), count);
+}
+
+} // namespace JSC
+
+#endif // WriteBarrier_h