summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/kjs
diff options
context:
space:
mode:
authorUpstream <upstream-import@none>1970-01-12 13:46:40 +0000
committerUpstream <upstream-import@none>1970-01-12 13:46:40 +0000
commitd8543bb6618c17b12da906afa77d216f58cf4058 (patch)
treec58dc05ed86825bd0ef8d305d58c8205106b540f /JavaScriptCore/kjs
downloadexternal_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.zip
external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.gz
external_webkit-d8543bb6618c17b12da906afa77d216f58cf4058.tar.bz2
external/webkit r30707
Diffstat (limited to 'JavaScriptCore/kjs')
-rw-r--r--JavaScriptCore/kjs/Activation.h100
-rw-r--r--JavaScriptCore/kjs/AllInOneFile.cpp72
-rw-r--r--JavaScriptCore/kjs/CollectorHeapIntrospector.cpp96
-rw-r--r--JavaScriptCore/kjs/CollectorHeapIntrospector.h75
-rw-r--r--JavaScriptCore/kjs/CommonIdentifiers.cpp47
-rw-r--r--JavaScriptCore/kjs/CommonIdentifiers.h72
-rw-r--r--JavaScriptCore/kjs/DateMath.cpp506
-rw-r--r--JavaScriptCore/kjs/DateMath.h154
-rw-r--r--JavaScriptCore/kjs/ExecState.cpp215
-rw-r--r--JavaScriptCore/kjs/ExecState.h235
-rw-r--r--JavaScriptCore/kjs/JSGlobalObject.cpp572
-rw-r--r--JavaScriptCore/kjs/JSGlobalObject.h255
-rw-r--r--JavaScriptCore/kjs/JSImmediate.cpp82
-rw-r--r--JavaScriptCore/kjs/JSImmediate.h278
-rw-r--r--JavaScriptCore/kjs/JSLock.cpp143
-rw-r--r--JavaScriptCore/kjs/JSLock.h81
-rw-r--r--JavaScriptCore/kjs/JSType.h43
-rw-r--r--JavaScriptCore/kjs/JSVariableObject.cpp106
-rw-r--r--JavaScriptCore/kjs/JSVariableObject.h135
-rw-r--r--JavaScriptCore/kjs/JSWrapperObject.cpp34
-rw-r--r--JavaScriptCore/kjs/JSWrapperObject.h84
-rw-r--r--JavaScriptCore/kjs/LabelStack.h84
-rw-r--r--JavaScriptCore/kjs/LocalStorage.h56
-rw-r--r--JavaScriptCore/kjs/NodeInfo.h44
-rw-r--r--JavaScriptCore/kjs/Parser.cpp91
-rw-r--r--JavaScriptCore/kjs/Parser.h99
-rw-r--r--JavaScriptCore/kjs/PropertyNameArray.cpp43
-rw-r--r--JavaScriptCore/kjs/PropertyNameArray.h56
-rw-r--r--JavaScriptCore/kjs/SavedBuiltins.h94
-rw-r--r--JavaScriptCore/kjs/SymbolTable.h68
-rw-r--r--JavaScriptCore/kjs/array_instance.cpp605
-rw-r--r--JavaScriptCore/kjs/array_instance.h72
-rw-r--r--JavaScriptCore/kjs/array_object.cpp760
-rw-r--r--JavaScriptCore/kjs/array_object.h71
-rw-r--r--JavaScriptCore/kjs/bool_object.cpp117
-rw-r--r--JavaScriptCore/kjs/bool_object.h65
-rw-r--r--JavaScriptCore/kjs/collector.cpp1054
-rw-r--r--JavaScriptCore/kjs/collector.h207
-rw-r--r--JavaScriptCore/kjs/completion.h60
-rw-r--r--JavaScriptCore/kjs/config.h91
-rwxr-xr-xJavaScriptCore/kjs/create_hash_table250
-rw-r--r--JavaScriptCore/kjs/date_object.cpp1669
-rw-r--r--JavaScriptCore/kjs/date_object.h135
-rw-r--r--JavaScriptCore/kjs/debugger.cpp134
-rw-r--r--JavaScriptCore/kjs/debugger.h225
-rw-r--r--JavaScriptCore/kjs/dtoa.cpp3300
-rw-r--r--JavaScriptCore/kjs/dtoa.h31
-rw-r--r--JavaScriptCore/kjs/error_object.cpp153
-rw-r--r--JavaScriptCore/kjs/error_object.h77
-rw-r--r--JavaScriptCore/kjs/function.cpp894
-rw-r--r--JavaScriptCore/kjs/function.h161
-rw-r--r--JavaScriptCore/kjs/function_object.cpp239
-rw-r--r--JavaScriptCore/kjs/function_object.h61
-rw-r--r--JavaScriptCore/kjs/grammar.y1261
-rw-r--r--JavaScriptCore/kjs/identifier.cpp205
-rw-r--r--JavaScriptCore/kjs/identifier.h100
-rw-r--r--JavaScriptCore/kjs/internal.cpp302
-rw-r--r--JavaScriptCore/kjs/internal.h117
-rw-r--r--JavaScriptCore/kjs/interpreter.cpp159
-rw-r--r--JavaScriptCore/kjs/interpreter.h71
-rw-r--r--JavaScriptCore/kjs/keywords.table72
-rw-r--r--JavaScriptCore/kjs/lexer.cpp897
-rw-r--r--JavaScriptCore/kjs/lexer.h149
-rw-r--r--JavaScriptCore/kjs/list.cpp76
-rw-r--r--JavaScriptCore/kjs/list.h118
-rw-r--r--JavaScriptCore/kjs/lookup.cpp81
-rw-r--r--JavaScriptCore/kjs/lookup.h340
-rw-r--r--JavaScriptCore/kjs/math_object.cpp243
-rw-r--r--JavaScriptCore/kjs/math_object.h65
-rw-r--r--JavaScriptCore/kjs/nodes.cpp4710
-rw-r--r--JavaScriptCore/kjs/nodes.h2907
-rw-r--r--JavaScriptCore/kjs/nodes2string.cpp973
-rw-r--r--JavaScriptCore/kjs/number_object.cpp522
-rw-r--r--JavaScriptCore/kjs/number_object.h76
-rw-r--r--JavaScriptCore/kjs/object.cpp660
-rw-r--r--JavaScriptCore/kjs/object.h586
-rw-r--r--JavaScriptCore/kjs/object_object.cpp216
-rw-r--r--JavaScriptCore/kjs/object_object.h57
-rw-r--r--JavaScriptCore/kjs/operations.cpp128
-rw-r--r--JavaScriptCore/kjs/operations.h35
-rw-r--r--JavaScriptCore/kjs/property_map.cpp850
-rw-r--r--JavaScriptCore/kjs/property_map.h184
-rw-r--r--JavaScriptCore/kjs/property_slot.cpp46
-rw-r--r--JavaScriptCore/kjs/property_slot.h142
-rw-r--r--JavaScriptCore/kjs/protect.h143
-rw-r--r--JavaScriptCore/kjs/regexp.cpp131
-rw-r--r--JavaScriptCore/kjs/regexp.h69
-rw-r--r--JavaScriptCore/kjs/regexp_object.cpp475
-rw-r--r--JavaScriptCore/kjs/regexp_object.h105
-rw-r--r--JavaScriptCore/kjs/scope_chain.cpp63
-rw-r--r--JavaScriptCore/kjs/scope_chain.h156
-rw-r--r--JavaScriptCore/kjs/scope_chain_mark.h49
-rw-r--r--JavaScriptCore/kjs/string_object.cpp1051
-rw-r--r--JavaScriptCore/kjs/string_object.h153
-rw-r--r--JavaScriptCore/kjs/testkjs.cpp374
-rw-r--r--JavaScriptCore/kjs/testkjs.pro38
-rw-r--r--JavaScriptCore/kjs/types.h25
-rw-r--r--JavaScriptCore/kjs/ustring.cpp1285
-rw-r--r--JavaScriptCore/kjs/ustring.h470
-rw-r--r--JavaScriptCore/kjs/value.cpp232
-rw-r--r--JavaScriptCore/kjs/value.h523
101 files changed, 36141 insertions, 0 deletions
diff --git a/JavaScriptCore/kjs/Activation.h b/JavaScriptCore/kjs/Activation.h
new file mode 100644
index 0000000..9291089
--- /dev/null
+++ b/JavaScriptCore/kjs/Activation.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2006, 2007 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 Activation_h
+#define Activation_h
+
+#include "ExecState.h"
+#include "JSVariableObject.h"
+#include "object.h"
+
+namespace KJS {
+
+ class Arguments;
+ class FunctionImp;
+
+ class ActivationImp : public JSVariableObject {
+ friend class JSGlobalObject;
+ friend struct StackActivation;
+ private:
+ struct ActivationData : public JSVariableObjectData {
+ ActivationData() : isOnStack(true), leftRelic(false) { }
+ ActivationData(const ActivationData&);
+
+ ExecState* exec;
+ FunctionImp* function;
+ Arguments* argumentsObject;
+
+ bool isOnStack : 1;
+ bool leftRelic : 1;
+ };
+
+ public:
+ ActivationImp() { }
+ ActivationImp(const ActivationData&, bool);
+
+ virtual ~ActivationImp();
+
+ void init(ExecState*);
+
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual void put(ExecState*, const Identifier&, JSValue*);
+ virtual void initializeVariable(ExecState*, const Identifier&, JSValue*, unsigned attributes);
+ virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+
+ virtual void mark();
+ void markChildren();
+
+ virtual bool isActivationObject() const { return true; }
+
+ bool isOnStack() const { return d()->isOnStack; }
+ bool needsPop() const { return d()->isOnStack || d()->leftRelic; }
+
+ private:
+ static PropertySlot::GetValueFunc getArgumentsGetter();
+ static JSValue* argumentsGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
+ void createArgumentsObject(ExecState*);
+ ActivationData* d() const { return static_cast<ActivationData*>(JSVariableObject::d); }
+ };
+
+ const size_t activationStackNodeSize = 32;
+
+ struct StackActivation {
+ StackActivation() { activationStorage.JSVariableObject::d = &activationDataStorage; }
+ StackActivation(const StackActivation&);
+
+ ActivationImp activationStorage;
+ ActivationImp::ActivationData activationDataStorage;
+ };
+
+ struct ActivationStackNode {
+ ActivationStackNode* prev;
+ StackActivation data[activationStackNodeSize];
+ };
+
+} // namespace
+
+#endif
diff --git a/JavaScriptCore/kjs/AllInOneFile.cpp b/JavaScriptCore/kjs/AllInOneFile.cpp
new file mode 100644
index 0000000..5144521
--- /dev/null
+++ b/JavaScriptCore/kjs/AllInOneFile.cpp
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2006 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.
+ *
+ */
+
+// This file exists to help compile the essential code of
+// JavaScriptCore all as one file, for compilers and build systems
+// that see a significant speed gain from this.
+
+#define KDE_USE_FINAL 1
+#include "config.h"
+
+#include "function.cpp"
+#include "debugger.cpp"
+#include "array_instance.cpp"
+#include "array_object.cpp"
+#include "bool_object.cpp"
+#include "collector.cpp"
+#if PLATFORM(DARWIN)
+#include "CollectorHeapIntrospector.cpp"
+#endif
+#include "CommonIdentifiers.cpp"
+#include "date_object.cpp"
+#include "DateMath.cpp"
+#include "dtoa.cpp"
+#include "error_object.cpp"
+#include "ExecState.cpp"
+#include "function_object.cpp"
+#include "grammar.cpp"
+#include "identifier.cpp"
+#include "internal.cpp"
+#include "interpreter.cpp"
+#include "JSImmediate.cpp"
+#include "JSLock.cpp"
+#include "JSWrapperObject.cpp"
+#include "lexer.cpp"
+#include "list.cpp"
+#include "lookup.cpp"
+#include "math_object.cpp"
+#include "nodes.cpp"
+#include "nodes2string.cpp"
+#include "number_object.cpp"
+#include "object.cpp"
+#include "object_object.cpp"
+#include "operations.cpp"
+#include "Parser.cpp"
+#include "property_map.cpp"
+#include "property_slot.cpp"
+#include "PropertyNameArray.cpp"
+#include "regexp.cpp"
+#include "regexp_object.cpp"
+#include "scope_chain.cpp"
+#include "string_object.cpp"
+#include "ustring.cpp"
+#include "value.cpp"
+#include "wtf/FastMalloc.cpp"
+#include "wtf/TCSystemAlloc.cpp"
diff --git a/JavaScriptCore/kjs/CollectorHeapIntrospector.cpp b/JavaScriptCore/kjs/CollectorHeapIntrospector.cpp
new file mode 100644
index 0000000..29ee738
--- /dev/null
+++ b/JavaScriptCore/kjs/CollectorHeapIntrospector.cpp
@@ -0,0 +1,96 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must 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 "CollectorHeapIntrospector.h"
+
+#include "collector.h"
+#include "MallocZoneSupport.h"
+
+using WTF::RemoteMemoryReader;
+
+namespace KJS {
+
+extern "C" {
+malloc_introspection_t jscore_collector_introspection = { &CollectorHeapIntrospector::enumerate, &CollectorHeapIntrospector::goodSize, &CollectorHeapIntrospector::check, &CollectorHeapIntrospector::print,
+ &CollectorHeapIntrospector::log, &CollectorHeapIntrospector::forceLock, &CollectorHeapIntrospector::forceUnlock, &CollectorHeapIntrospector::statistics };
+}
+
+void CollectorHeapIntrospector::init(CollectorHeap* primaryHeap, CollectorHeap* numberHeap)
+{
+ static CollectorHeapIntrospector zone(primaryHeap, numberHeap);
+}
+
+CollectorHeapIntrospector::CollectorHeapIntrospector(CollectorHeap* primaryHeap, CollectorHeap* numberHeap)
+ : m_primaryHeap(primaryHeap)
+ , m_numberHeap(numberHeap)
+{
+ memset(&m_zone, 0, sizeof(m_zone));
+ m_zone.zone_name = "JavaScriptCore Collector";
+ m_zone.size = &CollectorHeapIntrospector::size;
+ m_zone.malloc = &CollectorHeapIntrospector::zoneMalloc;
+ m_zone.calloc = &CollectorHeapIntrospector::zoneCalloc;
+ m_zone.realloc = &CollectorHeapIntrospector::zoneRealloc;
+ m_zone.free = &CollectorHeapIntrospector::zoneFree;
+ m_zone.valloc = &CollectorHeapIntrospector::zoneValloc;
+ m_zone.destroy = &CollectorHeapIntrospector::zoneDestroy;
+ m_zone.introspect = &jscore_collector_introspection;
+ malloc_zone_register(&m_zone);
+}
+
+kern_return_t CollectorHeapIntrospector::enumerate(task_t task, void* context, unsigned typeMask, vm_address_t zoneAddress, memory_reader_t reader, vm_range_recorder_t recorder)
+{
+ RemoteMemoryReader memoryReader(task, reader);
+ CollectorHeapIntrospector* zone = memoryReader(reinterpret_cast<CollectorHeapIntrospector*>(zoneAddress));
+ CollectorHeap* heaps[2] = {memoryReader(zone->m_primaryHeap), memoryReader(zone->m_numberHeap)};
+
+ if (!heaps[0]->blocks && !heaps[1]->blocks)
+ return 0;
+
+ for (int currentHeap = 0; currentHeap < 2; currentHeap++) {
+ CollectorHeap* heap = heaps[currentHeap];
+ CollectorBlock** blocks = memoryReader(heap->blocks);
+ for (unsigned i = 0; i < heap->usedBlocks; i++) {
+ vm_address_t remoteBlockAddress = reinterpret_cast<vm_address_t>(blocks[i]);
+ vm_range_t ptrRange = { remoteBlockAddress, sizeof(CollectorBlock) };
+
+ if (typeMask & (MALLOC_PTR_REGION_RANGE_TYPE | MALLOC_ADMIN_REGION_RANGE_TYPE))
+ (*recorder)(task, context, MALLOC_PTR_REGION_RANGE_TYPE, &ptrRange, 1);
+
+ // Recording individual cells causes frequent false-positives. Any garbage cells
+ // which have yet to be collected are labeled as leaks. Recording on a per-block
+ // basis provides less detail but avoids these false-positives.
+ if (memoryReader(blocks[i])->usedCells && (typeMask & MALLOC_PTR_IN_USE_RANGE_TYPE))
+ (*recorder)(task, context, MALLOC_PTR_IN_USE_RANGE_TYPE, &ptrRange, 1);
+ }
+ }
+
+ return 0;
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/CollectorHeapIntrospector.h b/JavaScriptCore/kjs/CollectorHeapIntrospector.h
new file mode 100644
index 0000000..76ba324
--- /dev/null
+++ b/JavaScriptCore/kjs/CollectorHeapIntrospector.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must 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 CollectorHeapIntrospector_h
+#define CollectorHeapIntrospector_h
+
+#include <malloc/malloc.h>
+#include "Assertions.h"
+
+namespace KJS {
+
+struct CollectorHeap;
+
+class CollectorHeapIntrospector {
+public:
+ static void init(CollectorHeap*, CollectorHeap*);
+ static kern_return_t enumerate(task_t, void* context, unsigned typeMask, vm_address_t zoneAddress, memory_reader_t, vm_range_recorder_t);
+ static size_t goodSize(malloc_zone_t*, size_t size) { return size; }
+ static boolean_t check(malloc_zone_t*) { return true; }
+ static void print(malloc_zone_t*, boolean_t) { }
+ static void log(malloc_zone_t*, void*) { }
+ static void forceLock(malloc_zone_t*) { }
+ static void forceUnlock(malloc_zone_t*) { }
+ static void statistics(malloc_zone_t*, malloc_statistics_t*) { }
+
+private:
+ CollectorHeapIntrospector(CollectorHeap*, CollectorHeap*);
+ static size_t size(malloc_zone_t*, const void*) { return 0; }
+ static void* zoneMalloc(malloc_zone_t*, size_t) { LOG_ERROR("malloc is not supported"); return 0; }
+ static void* zoneCalloc(malloc_zone_t*, size_t, size_t) { LOG_ERROR("calloc is not supported"); return 0; }
+ static void* zoneRealloc(malloc_zone_t*, void*, size_t) { LOG_ERROR("realloc is not supported"); return 0; }
+ static void* zoneValloc(malloc_zone_t*, size_t) { LOG_ERROR("valloc is not supported"); return 0; }
+ static void zoneDestroy(malloc_zone_t*) { }
+
+ static void zoneFree(malloc_zone_t*, void* ptr)
+ {
+ // Due to <rdar://problem/5671357> zoneFree may be called by the system free even if the pointer
+ // is not in this zone. When this happens, the pointer being freed was not allocated by any
+ // zone so we need to print a useful error for the application developer.
+ malloc_printf("*** error for object %p: pointer being freed was not allocated\n", ptr);
+ }
+
+ malloc_zone_t m_zone;
+ CollectorHeap* m_primaryHeap;
+ CollectorHeap* m_numberHeap;
+};
+
+}
+
+#endif // CollectorHeapIntrospector_h
diff --git a/JavaScriptCore/kjs/CommonIdentifiers.cpp b/JavaScriptCore/kjs/CommonIdentifiers.cpp
new file mode 100644
index 0000000..5f673b8
--- /dev/null
+++ b/JavaScriptCore/kjs/CommonIdentifiers.cpp
@@ -0,0 +1,47 @@
+/*
+ * Copyright (C) 2003, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "CommonIdentifiers.h"
+
+namespace KJS {
+
+const char* const nullCString = 0;
+
+#define INITIALIZE_PROPERTY_NAME(name) , name ( #name )
+
+CommonIdentifiers::CommonIdentifiers()
+ : nullIdentifier(nullCString)
+ , underscoreProto("__proto__")
+ KJS_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(INITIALIZE_PROPERTY_NAME)
+{
+}
+
+CommonIdentifiers* CommonIdentifiers::shared()
+{
+ static CommonIdentifiers* sharedInstance;
+ if (!sharedInstance) {
+ JSLock lock;
+ sharedInstance = new CommonIdentifiers;
+ }
+ return sharedInstance;
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/CommonIdentifiers.h b/JavaScriptCore/kjs/CommonIdentifiers.h
new file mode 100644
index 0000000..ae5c778
--- /dev/null
+++ b/JavaScriptCore/kjs/CommonIdentifiers.h
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2003,2007 Apple Computer, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_COMMON_IDENTIFIERS_H
+#define KJS_COMMON_IDENTIFIERS_H
+
+#include "identifier.h"
+#include <wtf/Noncopyable.h>
+
+// List of property names, passed to a macro so we can do set them up various
+// ways without repeating the list.
+#define KJS_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(macro) \
+ macro(arguments) \
+ macro(callee) \
+ macro(caller) \
+ macro(constructor) \
+ macro(fromCharCode) \
+ macro(global) \
+ macro(ignoreCase) \
+ macro(index) \
+ macro(input) \
+ macro(length) \
+ macro(message) \
+ macro(multiline) \
+ macro(name) \
+ macro(prototype) \
+ macro(source) \
+ macro(toExponential) \
+ macro(toFixed) \
+ macro(toLocaleString) \
+ macro(toPrecision) \
+ macro(toString) \
+ macro(valueOf)
+
+namespace KJS {
+
+ class CommonIdentifiers : Noncopyable {
+
+ private:
+ CommonIdentifiers();
+
+ public:
+ static CommonIdentifiers* shared();
+
+ const Identifier nullIdentifier;
+ const Identifier underscoreProto;
+
+#define KJS_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL(name) const Identifier name;
+ KJS_COMMON_IDENTIFIERS_EACH_PROPERTY_NAME(KJS_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL)
+#undef KJS_IDENTIFIER_DECLARE_PROPERTY_NAME_GLOBAL
+ };
+} // namespace KJS
+
+#endif // KJS_COMMON_IDENTIFIERS_H
+
diff --git a/JavaScriptCore/kjs/DateMath.cpp b/JavaScriptCore/kjs/DateMath.cpp
new file mode 100644
index 0000000..22816b3
--- /dev/null
+++ b/JavaScriptCore/kjs/DateMath.cpp
@@ -0,0 +1,506 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of either the Mozilla Public License Version 1.1, found at
+ * http://www.mozilla.org/MPL/ (the "MPL") or the GNU General Public
+ * License Version 2.0, found at http://www.fsf.org/copyleft/gpl.html
+ * (the "GPL"), in which case the provisions of the MPL or the GPL are
+ * applicable instead of those above. If you wish to allow use of your
+ * version of this file only under the terms of one of those two
+ * licenses (the MPL or the GPL) and not to allow others to use your
+ * version of this file under the LGPL, indicate your decision by
+ * deletingthe provisions above and replace them with the notice and
+ * other provisions required by the MPL or the GPL, as the case may be.
+ * If you do not delete the provisions above, a recipient may use your
+ * version of this file under any of the LGPL, the MPL or the GPL.
+ */
+
+#include "config.h"
+#include "DateMath.h"
+
+#include <math.h>
+#include <stdint.h>
+#include <value.h>
+
+#include <wtf/Assertions.h>
+
+#if PLATFORM(DARWIN)
+#include <notify.h>
+#endif
+
+#if HAVE(SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+#if HAVE(SYS_TIMEB_H)
+#include <sys/timeb.h>
+#endif
+
+namespace KJS {
+
+/* Constants */
+
+static const double minutesPerDay = 24.0 * 60.0;
+static const double secondsPerDay = 24.0 * 60.0 * 60.0;
+static const double secondsPerYear = 24.0 * 60.0 * 60.0 * 365.0;
+
+static const double usecPerSec = 1000000.0;
+
+static const double maxUnixTime = 2145859200.0; // 12/31/2037
+
+// Day of year for the first day of each month, where index 0 is January, and day 0 is January 1.
+// First for non-leap years, then for leap years.
+static const int firstDayOfMonth[2][12] = {
+ {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334},
+ {0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335}
+};
+
+static inline bool isLeapYear(int year)
+{
+ if (year % 4 != 0)
+ return false;
+ if (year % 400 == 0)
+ return true;
+ if (year % 100 == 0)
+ return false;
+ return true;
+}
+
+static inline int daysInYear(int year)
+{
+ return 365 + isLeapYear(year);
+}
+
+static inline double daysFrom1970ToYear(int year)
+{
+ // The Gregorian Calendar rules for leap years:
+ // Every fourth year is a leap year. 2004, 2008, and 2012 are leap years.
+ // However, every hundredth year is not a leap year. 1900 and 2100 are not leap years.
+ // Every four hundred years, there's a leap year after all. 2000 and 2400 are leap years.
+
+ static const int leapDaysBefore1971By4Rule = 1970 / 4;
+ static const int excludedLeapDaysBefore1971By100Rule = 1970 / 100;
+ static const int leapDaysBefore1971By400Rule = 1970 / 400;
+
+ const double yearMinusOne = year - 1;
+ const double yearsToAddBy4Rule = floor(yearMinusOne / 4.0) - leapDaysBefore1971By4Rule;
+ const double yearsToExcludeBy100Rule = floor(yearMinusOne / 100.0) - excludedLeapDaysBefore1971By100Rule;
+ const double yearsToAddBy400Rule = floor(yearMinusOne / 400.0) - leapDaysBefore1971By400Rule;
+
+ return 365.0 * (year - 1970) + yearsToAddBy4Rule - yearsToExcludeBy100Rule + yearsToAddBy400Rule;
+}
+
+static inline double msToDays(double ms)
+{
+ return floor(ms / msPerDay);
+}
+
+static inline int msToYear(double ms)
+{
+ int approxYear = static_cast<int>(floor(ms / (msPerDay * 365.2425)) + 1970);
+ double msFromApproxYearTo1970 = msPerDay * daysFrom1970ToYear(approxYear);
+ if (msFromApproxYearTo1970 > ms)
+ return approxYear - 1;
+ if (msFromApproxYearTo1970 + msPerDay * daysInYear(approxYear) <= ms)
+ return approxYear + 1;
+ return approxYear;
+}
+
+static inline int dayInYear(double ms, int year)
+{
+ return static_cast<int>(msToDays(ms) - daysFrom1970ToYear(year));
+}
+
+static inline double msToMilliseconds(double ms)
+{
+ double result = fmod(ms, msPerDay);
+ if (result < 0)
+ result += msPerDay;
+ return result;
+}
+
+// 0: Sunday, 1: Monday, etc.
+static inline int msToWeekDay(double ms)
+{
+ int wd = (static_cast<int>(msToDays(ms)) + 4) % 7;
+ if (wd < 0)
+ wd += 7;
+ return wd;
+}
+
+static inline int msToSeconds(double ms)
+{
+ double result = fmod(floor(ms / msPerSecond), secondsPerMinute);
+ if (result < 0)
+ result += secondsPerMinute;
+ return static_cast<int>(result);
+}
+
+static inline int msToMinutes(double ms)
+{
+ double result = fmod(floor(ms / msPerMinute), minutesPerHour);
+ if (result < 0)
+ result += minutesPerHour;
+ return static_cast<int>(result);
+}
+
+static inline int msToHours(double ms)
+{
+ double result = fmod(floor(ms/msPerHour), hoursPerDay);
+ if (result < 0)
+ result += hoursPerDay;
+ return static_cast<int>(result);
+}
+
+static inline int monthFromDayInYear(int dayInYear, bool leapYear)
+{
+ const int d = dayInYear;
+ int step;
+
+ if (d < (step = 31))
+ return 0;
+ step += (leapYear ? 29 : 28);
+ if (d < step)
+ return 1;
+ if (d < (step += 31))
+ return 2;
+ if (d < (step += 30))
+ return 3;
+ if (d < (step += 31))
+ return 4;
+ if (d < (step += 30))
+ return 5;
+ if (d < (step += 31))
+ return 6;
+ if (d < (step += 31))
+ return 7;
+ if (d < (step += 30))
+ return 8;
+ if (d < (step += 31))
+ return 9;
+ if (d < (step += 30))
+ return 10;
+ return 11;
+}
+
+static inline bool checkMonth(int dayInYear, int& startDayOfThisMonth, int& startDayOfNextMonth, int daysInThisMonth)
+{
+ startDayOfThisMonth = startDayOfNextMonth;
+ startDayOfNextMonth += daysInThisMonth;
+ return (dayInYear <= startDayOfNextMonth);
+}
+
+static inline int dayInMonthFromDayInYear(int dayInYear, bool leapYear)
+{
+ const int d = dayInYear;
+ int step;
+ int next = 30;
+
+ if (d <= next)
+ return d + 1;
+ const int daysInFeb = (leapYear ? 29 : 28);
+ if (checkMonth(d, step, next, daysInFeb))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ if (checkMonth(d, step, next, 31))
+ return d - step;
+ if (checkMonth(d, step, next, 30))
+ return d - step;
+ step = next;
+ return d - step;
+}
+
+static inline int monthToDayInYear(int month, bool isLeapYear)
+{
+ return firstDayOfMonth[isLeapYear][month];
+}
+
+static inline double timeToMS(double hour, double min, double sec, double ms)
+{
+ return (((hour * minutesPerHour + min) * secondsPerMinute + sec) * msPerSecond + ms);
+}
+
+static int dateToDayInYear(int year, int month, int day)
+{
+ year += month / 12;
+
+ month %= 12;
+ if (month < 0) {
+ month += 12;
+ --year;
+ }
+
+ int yearday = static_cast<int>(floor(daysFrom1970ToYear(year)));
+ int monthday = monthToDayInYear(month, isLeapYear(year));
+
+ return yearday + monthday + day - 1;
+}
+
+double getCurrentUTCTime()
+{
+#if PLATFORM(WIN_OS)
+#if COMPILER(BORLAND)
+ struct timeb timebuffer;
+ ftime(&timebuffer);
+#else
+ struct _timeb timebuffer;
+ _ftime(&timebuffer);
+#endif
+ double utc = timebuffer.time * msPerSecond + timebuffer.millitm;
+#else
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ double utc = floor(tv.tv_sec * msPerSecond + tv.tv_usec / 1000);
+#endif
+ return utc;
+}
+
+// There is a hard limit at 2038 that we currently do not have a workaround
+// for (rdar://problem/5052975).
+static inline int maximumYearForDST()
+{
+ return 2037;
+}
+
+// It is ok if the cached year is not the current year (e.g. Dec 31st)
+// so long as the rules for DST did not change between the two years, if it does
+// the app would need to be restarted.
+static int mimimumYearForDST()
+{
+ // Because of the 2038 issue (see maximumYearForDST) if the current year is
+ // greater than the max year minus 27 (2010), we want to use the max year
+ // minus 27 instead, to ensure there is a range of 28 years that all years
+ // can map to.
+ static int minYear = std::min(msToYear(getCurrentUTCTime()), maximumYearForDST() - 27) ;
+ return minYear;
+}
+
+/*
+ * Find an equivalent year for the one given, where equivalence is deterined by
+ * the two years having the same leapness and the first day of the year, falling
+ * on the same day of the week.
+ *
+ * This function returns a year between this current year and 2037, however this
+ * function will potentially return incorrect results if the current year is after
+ * 2010, (rdar://problem/5052975), if the year passed in is before 1900 or after
+ * 2100, (rdar://problem/5055038).
+ */
+int equivalentYearForDST(int year)
+{
+ static int minYear = mimimumYearForDST();
+ static int maxYear = maximumYearForDST();
+
+ int difference;
+ if (year > maxYear)
+ difference = minYear - year;
+ else if (year < minYear)
+ difference = maxYear - year;
+ else
+ return year;
+
+ int quotient = difference / 28;
+ int product = (quotient) * 28;
+
+ year += product;
+ ASSERT((year >= minYear && year <= maxYear) || (product - year == static_cast<int>(NaN)));
+ return year;
+}
+
+/*
+ * Get the difference in milliseconds between this time zone and UTC (GMT)
+ * NOT including DST.
+ */
+double getUTCOffset()
+{
+#if PLATFORM(DARWIN)
+ // Register for a notification whenever the time zone changes.
+ static bool triedToRegister = false;
+ static bool haveNotificationToken = false;
+ static int notificationToken;
+ if (!triedToRegister) {
+ triedToRegister = true;
+ uint32_t status = notify_register_check("com.apple.system.timezone", &notificationToken);
+ if (status == NOTIFY_STATUS_OK)
+ haveNotificationToken = true;
+ }
+
+ // If we can verify that we have not received a time zone notification,
+ // then use the cached offset from the last time this function was called.
+ static bool haveCachedOffset = false;
+ static double cachedOffset;
+ if (haveNotificationToken && haveCachedOffset) {
+ int notified;
+ uint32_t status = notify_check(notificationToken, &notified);
+ if (status == NOTIFY_STATUS_OK && !notified)
+ return cachedOffset;
+ }
+#endif
+
+ tm localt;
+
+ memset(&localt, 0, sizeof(localt));
+
+ // get the difference between this time zone and UTC on Jan 01, 2000 12:00:00 AM
+ localt.tm_mday = 1;
+ localt.tm_year = 100;
+ double utcOffset = 946684800.0 - mktime(&localt);
+
+ utcOffset *= msPerSecond;
+
+#if PLATFORM(DARWIN)
+ haveCachedOffset = true;
+ cachedOffset = utcOffset;
+#endif
+
+ return utcOffset;
+}
+
+/*
+ * Get the DST offset for the time passed in. Takes
+ * seconds (not milliseconds) and cannot handle dates before 1970
+ * on some OS'
+ */
+static double getDSTOffsetSimple(double localTimeSeconds, double utcOffset)
+{
+ if (localTimeSeconds > maxUnixTime)
+ localTimeSeconds = maxUnixTime;
+ else if (localTimeSeconds < 0) // Go ahead a day to make localtime work (does not work with 0)
+ localTimeSeconds += secondsPerDay;
+
+ //input is UTC so we have to shift back to local time to determine DST thus the + getUTCOffset()
+ double offsetTime = (localTimeSeconds * msPerSecond) + utcOffset;
+
+ // Offset from UTC but doesn't include DST obviously
+ int offsetHour = msToHours(offsetTime);
+ int offsetMinute = msToMinutes(offsetTime);
+
+ // FIXME: time_t has a potential problem in 2038
+ time_t localTime = static_cast<time_t>(localTimeSeconds);
+
+ tm localTM;
+#if PLATFORM(QT)
+ // ### this is not threadsafe but we don't use multiple threads anyway
+ // in the Qt build
+#if USE(MULTIPLE_THREADS)
+#error Mulitple threads are currently not supported in the Qt/mingw build
+#endif
+ localTM = *localtime(&localTime);
+#elif PLATFORM(WIN_OS)
+ #if COMPILER(MSVC7)
+ localTM = *localtime(&localTime);
+ #else
+ localtime_s(&localTM, &localTime);
+ #endif
+#else
+ localtime_r(&localTime, &localTM);
+#endif
+
+ double diff = ((localTM.tm_hour - offsetHour) * secondsPerHour) + ((localTM.tm_min - offsetMinute) * 60);
+
+ if (diff < 0)
+ diff += secondsPerDay;
+
+ return (diff * msPerSecond);
+}
+
+// Get the DST offset, given a time in UTC
+static double getDSTOffset(double ms, double utcOffset)
+{
+ // On Mac OS X, the call to localtime (see getDSTOffsetSimple) will return historically accurate
+ // DST information (e.g. New Zealand did not have DST from 1946 to 1974) however the JavaScript
+ // standard explicitly dictates that historical information should not be considered when
+ // determining DST. For this reason we shift away from years that localtime can handle but would
+ // return historically accurate information.
+ int year = msToYear(ms);
+ int equivalentYear = equivalentYearForDST(year);
+ if (year != equivalentYear) {
+ bool leapYear = isLeapYear(year);
+ int dayInYearLocal = dayInYear(ms, year);
+ int dayInMonth = dayInMonthFromDayInYear(dayInYearLocal, leapYear);
+ int month = monthFromDayInYear(dayInYearLocal, leapYear);
+ int day = dateToDayInYear(equivalentYear, month, dayInMonth);
+ ms = (day * msPerDay) + msToMilliseconds(ms);
+ }
+
+ return getDSTOffsetSimple(ms / msPerSecond, utcOffset);
+}
+
+double gregorianDateTimeToMS(const GregorianDateTime& t, double milliSeconds, bool inputIsUTC)
+{
+ int day = dateToDayInYear(t.year + 1900, t.month, t.monthDay);
+ double ms = timeToMS(t.hour, t.minute, t.second, milliSeconds);
+ double result = (day * msPerDay) + ms;
+
+ if (!inputIsUTC) { // convert to UTC
+ double utcOffset = getUTCOffset();
+ result -= utcOffset;
+ result -= getDSTOffset(result, utcOffset);
+ }
+
+ return result;
+}
+
+void msToGregorianDateTime(double ms, bool outputIsUTC, GregorianDateTime& tm)
+{
+ // input is UTC
+ double dstOff = 0.0;
+ const double utcOff = getUTCOffset();
+
+ if (!outputIsUTC) { // convert to local time
+ dstOff = getDSTOffset(ms, utcOff);
+ ms += dstOff + utcOff;
+ }
+
+ const int year = msToYear(ms);
+ tm.second = msToSeconds(ms);
+ tm.minute = msToMinutes(ms);
+ tm.hour = msToHours(ms);
+ tm.weekDay = msToWeekDay(ms);
+ tm.yearDay = dayInYear(ms, year);
+ tm.monthDay = dayInMonthFromDayInYear(tm.yearDay, isLeapYear(year));
+ tm.month = monthFromDayInYear(tm.yearDay, isLeapYear(year));
+ tm.year = year - 1900;
+ tm.isDST = dstOff != 0.0;
+
+ tm.utcOffset = static_cast<long>((dstOff + utcOff) / msPerSecond);
+ tm.timeZone = NULL;
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/DateMath.h b/JavaScriptCore/kjs/DateMath.h
new file mode 100644
index 0000000..6fdad0b
--- /dev/null
+++ b/JavaScriptCore/kjs/DateMath.h
@@ -0,0 +1,154 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * Version: MPL 1.1/GPL 2.0/LGPL 2.1
+ *
+ * The contents of this file are subject to the Mozilla Public License Version
+ * 1.1 (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS" basis,
+ * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
+ * for the specific language governing rights and limitations under the
+ * License.
+ *
+ * The Original Code is Mozilla Communicator client code, released
+ * March 31, 1998.
+ *
+ * The Initial Developer of the Original Code is
+ * Netscape Communications Corporation.
+ * Portions created by the Initial Developer are Copyright (C) 1998
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *
+ * Alternatively, the contents of this file may be used under the terms of
+ * either of the GNU General Public License Version 2 or later (the "GPL"),
+ * or the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
+ * in which case the provisions of the GPL or the LGPL are applicable instead
+ * of those above. If you wish to allow use of your version of this file only
+ * under the terms of either the GPL or the LGPL, and not to allow others to
+ * use your version of this file under the terms of the MPL, indicate your
+ * decision by deleting the provisions above and replace them with the notice
+ * and other provisions required by the GPL or the LGPL. If you do not delete
+ * the provisions above, a recipient may use your version of this file under
+ * the terms of any one of the MPL, the GPL or the LGPL.
+ *
+ */
+
+#ifndef DateMath_h
+#define DateMath_h
+
+#include <time.h>
+#include <string.h>
+#include <wtf/Noncopyable.h>
+
+namespace KJS {
+
+struct GregorianDateTime;
+
+void msToGregorianDateTime(double, bool outputIsUTC, GregorianDateTime&);
+double gregorianDateTimeToMS(const GregorianDateTime&, double, bool inputIsUTC);
+double getUTCOffset();
+int equivalentYearForDST(int year);
+double getCurrentUTCTime();
+
+const char * const weekdayName[7] = { "Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun" };
+const char * const monthName[12] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" };
+
+const double hoursPerDay = 24.0;
+const double minutesPerHour = 60.0;
+const double secondsPerHour = 60.0 * 60.0;
+const double secondsPerMinute = 60.0;
+const double msPerSecond = 1000.0;
+const double msPerMinute = 60.0 * 1000.0;
+const double msPerHour = 60.0 * 60.0 * 1000.0;
+const double msPerDay = 24.0 * 60.0 * 60.0 * 1000.0;
+
+// Intentionally overridding the default tm of the system
+// Tee members of tm differ on various operating systems.
+struct GregorianDateTime : Noncopyable {
+ GregorianDateTime()
+ : second(0)
+ , minute(0)
+ , hour(0)
+ , weekDay(0)
+ , monthDay(0)
+ , yearDay(0)
+ , month(0)
+ , year(0)
+ , isDST(0)
+ , utcOffset(0)
+ , timeZone(0)
+ {
+ }
+
+ ~GregorianDateTime()
+ {
+ delete [] timeZone;
+ }
+
+ GregorianDateTime(const tm& inTm)
+ : second(inTm.tm_sec)
+ , minute(inTm.tm_min)
+ , hour(inTm.tm_hour)
+ , weekDay(inTm.tm_wday)
+ , monthDay(inTm.tm_mday)
+ , yearDay(inTm.tm_yday)
+ , month(inTm.tm_mon)
+ , year(inTm.tm_year)
+ , isDST(inTm.tm_isdst)
+ {
+#if !PLATFORM(WIN_OS) && !PLATFORM(SOLARIS)
+ utcOffset = static_cast<int>(inTm.tm_gmtoff);
+
+ int inZoneSize = strlen(inTm.tm_zone) + 1;
+ timeZone = new char[inZoneSize];
+ strncpy(timeZone, inTm.tm_zone, inZoneSize);
+#else
+ utcOffset = static_cast<int>(getUTCOffset() / msPerSecond + (isDST ? secondsPerHour : 0));
+ timeZone = 0;
+#endif
+ }
+
+ operator tm() const
+ {
+ tm ret;
+ memset(&ret, 0, sizeof(ret));
+
+ ret.tm_sec = second;
+ ret.tm_min = minute;
+ ret.tm_hour = hour;
+ ret.tm_wday = weekDay;
+ ret.tm_mday = monthDay;
+ ret.tm_yday = yearDay;
+ ret.tm_mon = month;
+ ret.tm_year = year;
+ ret.tm_isdst = isDST;
+
+#if !PLATFORM(WIN_OS) && !PLATFORM(SOLARIS)
+ ret.tm_gmtoff = static_cast<long>(utcOffset);
+ ret.tm_zone = timeZone;
+#endif
+
+ return ret;
+ }
+
+ int second;
+ int minute;
+ int hour;
+ int weekDay;
+ int monthDay;
+ int yearDay;
+ int month;
+ int year;
+ int isDST;
+ int utcOffset;
+ char* timeZone;
+};
+
+} //namespace KJS
+
+#endif // DateMath_h
diff --git a/JavaScriptCore/kjs/ExecState.cpp b/JavaScriptCore/kjs/ExecState.cpp
new file mode 100644
index 0000000..b37523e
--- /dev/null
+++ b/JavaScriptCore/kjs/ExecState.cpp
@@ -0,0 +1,215 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * 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 "ExecState.h"
+
+#include "Activation.h"
+#include "JSGlobalObject.h"
+#include "function.h"
+#include "internal.h"
+#include "scope_chain_mark.h"
+
+namespace KJS {
+
+static inline List* globalEmptyList()
+{
+ static List staticEmptyList;
+ return &staticEmptyList;
+}
+
+// ECMA 10.2
+
+// The constructor for the globalExec pseudo-ExecState
+inline ExecState::ExecState(JSGlobalObject* globalObject)
+ : m_globalObject(globalObject)
+ , m_exception(0)
+ , m_propertyNames(CommonIdentifiers::shared())
+ , m_emptyList(globalEmptyList())
+ , m_callingExec(0)
+ , m_scopeNode(0)
+ , m_function(0)
+ , m_arguments(0)
+ , m_activation(0)
+ , m_localStorage(&globalObject->localStorage())
+ , m_variableObject(globalObject)
+ , m_thisValue(globalObject)
+ , m_iterationDepth(0)
+ , m_switchDepth(0)
+ , m_codeType(GlobalCode)
+{
+ m_scopeChain.push(globalObject);
+}
+
+inline ExecState::ExecState(JSGlobalObject* globalObject, JSObject* /*thisObject*/, ProgramNode* programNode)
+ : m_globalObject(globalObject)
+ , m_exception(0)
+ , m_propertyNames(CommonIdentifiers::shared())
+ , m_emptyList(globalEmptyList())
+ , m_callingExec(0)
+ , m_scopeNode(programNode)
+ , m_function(0)
+ , m_arguments(0)
+ , m_activation(0)
+ , m_localStorage(&globalObject->localStorage())
+ , m_variableObject(globalObject)
+ , m_thisValue(globalObject)
+ , m_iterationDepth(0)
+ , m_switchDepth(0)
+ , m_codeType(GlobalCode)
+{
+ // FIXME: This function ignores the "thisObject" parameter, which means that the API for evaluating
+ // a script with a this object that's not the same as the global object is broken, and probably
+ // has been for some time.
+ ASSERT(m_scopeNode);
+ m_scopeChain.push(globalObject);
+}
+
+inline ExecState::ExecState(JSGlobalObject* globalObject, EvalNode* evalNode, ExecState* callingExec)
+ : m_globalObject(globalObject)
+ , m_exception(0)
+ , m_propertyNames(callingExec->m_propertyNames)
+ , m_emptyList(callingExec->m_emptyList)
+ , m_callingExec(callingExec)
+ , m_scopeNode(evalNode)
+ , m_function(0)
+ , m_arguments(0)
+ , m_activation(0)
+ , m_localStorage(callingExec->m_localStorage)
+ , m_scopeChain(callingExec->m_scopeChain)
+ , m_variableObject(callingExec->m_variableObject)
+ , m_thisValue(callingExec->m_thisValue)
+ , m_iterationDepth(0)
+ , m_switchDepth(0)
+ , m_codeType(EvalCode)
+{
+ ASSERT(m_scopeNode);
+}
+
+inline ExecState::ExecState(JSGlobalObject* globalObject, JSObject* thisObject,
+ FunctionBodyNode* functionBodyNode, ExecState* callingExec,
+ FunctionImp* func, const List& args)
+ : m_globalObject(globalObject)
+ , m_exception(0)
+ , m_propertyNames(callingExec->m_propertyNames)
+ , m_emptyList(callingExec->m_emptyList)
+ , m_callingExec(callingExec)
+ , m_scopeNode(functionBodyNode)
+ , m_function(func)
+ , m_arguments(&args)
+ , m_scopeChain(func->scope())
+ , m_thisValue(thisObject)
+ , m_iterationDepth(0)
+ , m_switchDepth(0)
+ , m_codeType(FunctionCode)
+{
+ ASSERT(m_scopeNode);
+
+ ActivationImp* activation = globalObject->pushActivation(this);
+ m_activation = activation;
+ m_localStorage = &activation->localStorage();
+ m_variableObject = activation;
+ m_scopeChain.push(activation);
+}
+
+inline ExecState::~ExecState()
+{
+}
+
+JSGlobalObject* ExecState::lexicalGlobalObject() const
+{
+ JSObject* object = m_scopeChain.bottom();
+ if (object && object->isGlobalObject())
+ return static_cast<JSGlobalObject*>(object);
+ return m_globalObject;
+}
+
+void ExecState::markActiveExecStates()
+{
+ ExecStateStack::const_iterator end = activeExecStates().end();
+ for (ExecStateStack::const_iterator it = activeExecStates().begin(); it != end; ++it)
+ (*it)->m_scopeChain.mark();
+}
+
+static inline ExecStateStack& inlineActiveExecStates()
+{
+ static ExecStateStack staticActiveExecStates;
+ return staticActiveExecStates;
+}
+
+ExecStateStack& ExecState::activeExecStates()
+{
+ return inlineActiveExecStates();
+}
+
+GlobalExecState::GlobalExecState(JSGlobalObject* globalObject)
+ : ExecState(globalObject)
+{
+}
+
+GlobalExecState::~GlobalExecState()
+{
+}
+
+InterpreterExecState::InterpreterExecState(JSGlobalObject* globalObject, JSObject* thisObject, ProgramNode* programNode)
+ : ExecState(globalObject, thisObject, programNode)
+{
+ inlineActiveExecStates().append(this);
+}
+
+InterpreterExecState::~InterpreterExecState()
+{
+ ASSERT(inlineActiveExecStates().last() == this);
+ inlineActiveExecStates().removeLast();
+}
+
+EvalExecState::EvalExecState(JSGlobalObject* globalObject, EvalNode* evalNode, ExecState* callingExec)
+ : ExecState(globalObject, evalNode, callingExec)
+{
+ inlineActiveExecStates().append(this);
+}
+
+EvalExecState::~EvalExecState()
+{
+ ASSERT(inlineActiveExecStates().last() == this);
+ inlineActiveExecStates().removeLast();
+}
+
+FunctionExecState::FunctionExecState(JSGlobalObject* globalObject, JSObject* thisObject,
+ FunctionBodyNode* functionBodyNode, ExecState* callingExec,
+ FunctionImp* func, const List& args)
+ : ExecState(globalObject, thisObject, functionBodyNode, callingExec, func, args)
+{
+ inlineActiveExecStates().append(this);
+}
+
+FunctionExecState::~FunctionExecState()
+{
+ ASSERT(inlineActiveExecStates().last() == this);
+ inlineActiveExecStates().removeLast();
+
+ if (m_activation->needsPop())
+ m_globalObject->popActivation();
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/ExecState.h b/JavaScriptCore/kjs/ExecState.h
new file mode 100644
index 0000000..ffa067d
--- /dev/null
+++ b/JavaScriptCore/kjs/ExecState.h
@@ -0,0 +1,235 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef ExecState_h
+#define ExecState_h
+
+#include "LabelStack.h"
+#include "LocalStorage.h"
+#include "completion.h"
+#include "list.h"
+#include "scope_chain.h"
+
+namespace KJS {
+
+ class ActivationImp;
+ class CommonIdentifiers;
+ class EvalNode;
+ class FunctionBodyNode;
+ class FunctionImp;
+ class GlobalFuncImp;
+ class Interpreter;
+ class JSGlobalObject;
+ class JSVariableObject;
+ class ProgramNode;
+ class ScopeNode;
+
+ enum CodeType { GlobalCode, EvalCode, FunctionCode };
+
+ typedef Vector<ExecState*, 16> ExecStateStack;
+
+ // Represents the current state of script execution.
+ // Passed as the first argument to most functions.
+ class ExecState : Noncopyable {
+ public:
+ // Global object that was in scope when the current script started executing.
+ JSGlobalObject* dynamicGlobalObject() const { return m_globalObject; }
+
+ // Global object that was in scope when the current body of code was defined.
+ JSGlobalObject* lexicalGlobalObject() const;
+
+ void setException(JSValue* exception) { m_exception = exception; }
+ void clearException() { m_exception = 0; }
+ JSValue* exception() const { return m_exception; }
+ JSValue** exceptionSlot() { return &m_exception; }
+ bool hadException() const { return !!m_exception; }
+ JSValue* takeException() { JSValue* exception = m_exception; m_exception = 0; return exception; }
+
+ const ScopeChain& scopeChain() const { return m_scopeChain; }
+ void pushScope(JSObject* s) { m_scopeChain.push(s); }
+ void popScope() { m_scopeChain.pop(); }
+ void replaceScopeChainTop(JSObject* o) { m_scopeChain.replaceTop(o); }
+
+ JSVariableObject* variableObject() const { return m_variableObject; }
+ void setVariableObject(JSVariableObject* v) { m_variableObject = v; }
+
+ JSObject* thisValue() const { return m_thisValue; }
+
+ ExecState* callingExecState() { return m_callingExec; }
+
+ ActivationImp* activationObject() { return m_activation; }
+ void setActivationObject(ActivationImp* a) { m_activation = a; }
+ CodeType codeType() { return m_codeType; }
+ ScopeNode* scopeNode() { return m_scopeNode; }
+ FunctionImp* function() const { return m_function; }
+ const List* arguments() const { return m_arguments; }
+
+ LabelStack& seenLabels() { return m_labelStack; }
+
+ void pushIteration() { m_iterationDepth++; }
+ void popIteration() { m_iterationDepth--; }
+ bool inIteration() const { return (m_iterationDepth > 0); }
+
+ void pushSwitch() { m_switchDepth++; }
+ void popSwitch() { m_switchDepth--; }
+ bool inSwitch() const { return (m_switchDepth > 0); }
+
+ // These pointers are used to avoid accessing global variables for these,
+ // to avoid taking PIC branches in Mach-O binaries.
+ const CommonIdentifiers& propertyNames() const { return *m_propertyNames; }
+ const List& emptyList() const { return *m_emptyList; }
+
+ LocalStorage& localStorage() { return *m_localStorage; }
+ void setLocalStorage(LocalStorage* s) { m_localStorage = s; }
+
+ // These are only valid right after calling execute().
+ ComplType completionType() const { return m_completionType; }
+ const Identifier& breakOrContinueTarget() const
+ {
+ ASSERT(m_completionType == Break || m_completionType == Continue);
+ return *m_breakOrContinueTarget;
+ }
+
+ // Only for use in the implementation of execute().
+ void setCompletionType(ComplType type)
+ {
+ ASSERT(type != Break);
+ ASSERT(type != Continue);
+ m_completionType = type;
+ }
+ JSValue* setNormalCompletion()
+ {
+ ASSERT(!hadException());
+ m_completionType = Normal;
+ return 0;
+ }
+ JSValue* setNormalCompletion(JSValue* value)
+ {
+ ASSERT(!hadException());
+ m_completionType = Normal;
+ return value;
+ }
+ JSValue* setBreakCompletion(const Identifier* target)
+ {
+ ASSERT(!hadException());
+ m_completionType = Break;
+ m_breakOrContinueTarget = target;
+ return 0;
+ }
+ JSValue* setContinueCompletion(const Identifier* target)
+ {
+ ASSERT(!hadException());
+ m_completionType = Continue;
+ m_breakOrContinueTarget = target;
+ return 0;
+ }
+ JSValue* setReturnValueCompletion(JSValue* returnValue)
+ {
+ ASSERT(!hadException());
+ ASSERT(returnValue);
+ m_completionType = ReturnValue;
+ return returnValue;
+ }
+ JSValue* setThrowCompletion(JSValue* exception)
+ {
+ ASSERT(!hadException());
+ ASSERT(exception);
+ m_completionType = Throw;
+ return exception;
+ }
+ JSValue* setInterruptedCompletion()
+ {
+ ASSERT(!hadException());
+ m_completionType = Interrupted;
+ return 0;
+ }
+
+ static void markActiveExecStates();
+ static ExecStateStack& activeExecStates();
+
+ protected:
+ ExecState(JSGlobalObject*);
+ ExecState(JSGlobalObject*, JSObject* thisObject, ProgramNode*);
+ ExecState(JSGlobalObject*, EvalNode*, ExecState* callingExecState);
+ ExecState(JSGlobalObject*, JSObject* thisObject, FunctionBodyNode*,
+ ExecState* callingExecState, FunctionImp*, const List& args);
+ ~ExecState();
+
+ // ExecStates are always stack-allocated, and the garbage collector
+ // marks the stack, so we don't need to protect the objects below from GC.
+
+ JSGlobalObject* m_globalObject;
+ JSValue* m_exception;
+ CommonIdentifiers* m_propertyNames;
+ const List* m_emptyList;
+
+ ExecState* m_callingExec;
+
+ ScopeNode* m_scopeNode;
+
+ FunctionImp* m_function;
+ const List* m_arguments;
+ ActivationImp* m_activation;
+ LocalStorage* m_localStorage;
+
+ ScopeChain m_scopeChain;
+ JSVariableObject* m_variableObject;
+ JSObject* m_thisValue;
+
+ LabelStack m_labelStack;
+ int m_iterationDepth;
+ int m_switchDepth;
+ CodeType m_codeType;
+
+ ComplType m_completionType;
+ const Identifier* m_breakOrContinueTarget;
+ };
+
+ class GlobalExecState : public ExecState {
+ public:
+ GlobalExecState(JSGlobalObject*);
+ ~GlobalExecState();
+ };
+
+ class InterpreterExecState : public ExecState {
+ public:
+ InterpreterExecState(JSGlobalObject*, JSObject* thisObject, ProgramNode*);
+ ~InterpreterExecState();
+ };
+
+ class EvalExecState : public ExecState {
+ public:
+ EvalExecState(JSGlobalObject*, EvalNode*, ExecState* callingExecState);
+ ~EvalExecState();
+ };
+
+ class FunctionExecState : public ExecState {
+ public:
+ FunctionExecState(JSGlobalObject*, JSObject* thisObject, FunctionBodyNode*,
+ ExecState* callingExecState, FunctionImp*, const List& args);
+ ~FunctionExecState();
+ };
+
+} // namespace KJS
+
+#endif // ExecState_h
diff --git a/JavaScriptCore/kjs/JSGlobalObject.cpp b/JavaScriptCore/kjs/JSGlobalObject.cpp
new file mode 100644
index 0000000..aaf11e3
--- /dev/null
+++ b/JavaScriptCore/kjs/JSGlobalObject.cpp
@@ -0,0 +1,572 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSGlobalObject.h"
+
+#include "Activation.h"
+#include "array_object.h"
+#include "bool_object.h"
+#include "date_object.h"
+#include "debugger.h"
+#include "error_object.h"
+#include "function_object.h"
+#include "math_object.h"
+#include "number_object.h"
+#include "object_object.h"
+#include "regexp_object.h"
+#include "SavedBuiltins.h"
+#include "string_object.h"
+
+#if HAVE(SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+#if PLATFORM(WIN_OS)
+#include <windows.h>
+#endif
+
+#if PLATFORM(QT)
+#include <QDateTime>
+#endif
+
+namespace KJS {
+
+// Default number of ticks before a timeout check should be done.
+static const int initialTickCountThreshold = 255;
+
+// Preferred number of milliseconds between each timeout check
+static const int preferredScriptCheckTimeInterval = 1000;
+
+static inline void markIfNeeded(JSValue* v)
+{
+ if (v && !v->marked())
+ v->mark();
+}
+
+// Returns the current time in milliseconds
+// It doesn't matter what "current time" is here, just as long as
+// it's possible to measure the time difference correctly.
+static inline unsigned getCurrentTime()
+{
+#if HAVE(SYS_TIME_H)
+ struct timeval tv;
+ gettimeofday(&tv, 0);
+ return tv.tv_sec * 1000 + tv.tv_usec / 1000;
+#elif PLATFORM(QT)
+ QDateTime t = QDateTime::currentDateTime();
+ return t.toTime_t() * 1000 + t.time().msec();
+#elif PLATFORM(WIN_OS)
+ return timeGetTime();
+#else
+#error Platform does not have getCurrentTime function
+#endif
+}
+
+JSGlobalObject* JSGlobalObject::s_head = 0;
+
+void JSGlobalObject::deleteActivationStack()
+{
+ ActivationStackNode* prevNode = 0;
+ for (ActivationStackNode* currentNode = d()->activations; currentNode; currentNode = prevNode) {
+ prevNode = currentNode->prev;
+ delete currentNode;
+ }
+}
+
+JSGlobalObject::~JSGlobalObject()
+{
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ if (d()->debugger)
+ d()->debugger->detach(this);
+
+ d()->next->d()->prev = d()->prev;
+ d()->prev->d()->next = d()->next;
+ s_head = d()->next;
+ if (s_head == this)
+ s_head = 0;
+
+ deleteActivationStack();
+
+ delete d();
+}
+
+void JSGlobalObject::init()
+{
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ if (s_head) {
+ d()->prev = s_head;
+ d()->next = s_head->d()->next;
+ s_head->d()->next->d()->prev = this;
+ s_head->d()->next = this;
+ } else
+ s_head = d()->next = d()->prev = this;
+
+ resetTimeoutCheck();
+ d()->timeoutTime = 0;
+ d()->timeoutCheckCount = 0;
+
+ d()->recursion = 0;
+ d()->debugger = 0;
+
+ ActivationStackNode* newStackNode = new ActivationStackNode;
+ newStackNode->prev = 0;
+ d()->activations = newStackNode;
+ d()->activationCount = 0;
+
+ reset(prototype());
+}
+
+bool JSGlobalObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (symbolTableGet(propertyName, slot))
+ return true;
+ return JSVariableObject::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+void JSGlobalObject::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
+{
+ if (symbolTablePut(propertyName, value))
+ return;
+ return JSVariableObject::put(exec, propertyName, value);
+}
+
+void JSGlobalObject::initializeVariable(ExecState* exec, const Identifier& propertyName, JSValue* value, unsigned attributes)
+{
+ if (symbolTableInitializeVariable(propertyName, value, attributes))
+ return;
+
+ JSValue* valueBefore = getDirect(propertyName);
+ JSVariableObject::put(exec, propertyName, value);
+ if (!valueBefore) {
+ if (JSValue* valueAfter = getDirect(propertyName))
+ putDirect(propertyName, valueAfter, attributes);
+ }
+}
+
+static inline JSObject* lastInPrototypeChain(JSObject* object)
+{
+ JSObject* o = object;
+ while (o->prototype()->isObject())
+ o = static_cast<JSObject*>(o->prototype());
+ return o;
+}
+
+void JSGlobalObject::reset(JSValue* prototype)
+{
+ // Clear before inititalizing, to avoid calling mark() on stale pointers --
+ // which would be wasteful -- or uninitialized pointers -- which would be
+ // dangerous. (The allocations below may cause a GC.)
+
+ _prop.clear();
+ localStorage().clear();
+ symbolTable().clear();
+
+ // Prototypes
+ d()->functionPrototype = 0;
+ d()->objectPrototype = 0;
+
+ d()->arrayPrototype = 0;
+ d()->stringPrototype = 0;
+ d()->booleanPrototype = 0;
+ d()->numberPrototype = 0;
+ d()->datePrototype = 0;
+ d()->regExpPrototype = 0;
+ d()->errorPrototype = 0;
+
+ d()->evalErrorPrototype = 0;
+ d()->rangeErrorPrototype = 0;
+ d()->referenceErrorPrototype = 0;
+ d()->syntaxErrorPrototype = 0;
+ d()->typeErrorPrototype = 0;
+ d()->URIErrorPrototype = 0;
+
+ // Constructors
+ d()->objectConstructor = 0;
+ d()->functionConstructor = 0;
+ d()->arrayConstructor = 0;
+ d()->stringConstructor = 0;
+ d()->booleanConstructor = 0;
+ d()->numberConstructor = 0;
+ d()->dateConstructor = 0;
+ d()->regExpConstructor = 0;
+ d()->errorConstructor = 0;
+
+ d()->evalErrorConstructor = 0;
+ d()->rangeErrorConstructor = 0;
+ d()->referenceErrorConstructor = 0;
+ d()->syntaxErrorConstructor = 0;
+ d()->typeErrorConstructor = 0;
+ d()->URIErrorConstructor = 0;
+
+ ExecState* exec = &d()->globalExec;
+
+ // Prototypes
+ d()->functionPrototype = new FunctionPrototype(exec);
+ d()->objectPrototype = new ObjectPrototype(exec, d()->functionPrototype);
+ d()->functionPrototype->setPrototype(d()->objectPrototype);
+
+ d()->arrayPrototype = new ArrayPrototype(exec, d()->objectPrototype);
+ d()->stringPrototype = new StringPrototype(exec, d()->objectPrototype);
+ d()->booleanPrototype = new BooleanPrototype(exec, d()->objectPrototype, d()->functionPrototype);
+ d()->numberPrototype = new NumberPrototype(exec, d()->objectPrototype, d()->functionPrototype);
+ d()->datePrototype = new DatePrototype(exec, d()->objectPrototype);
+ d()->regExpPrototype = new RegExpPrototype(exec, d()->objectPrototype, d()->functionPrototype);
+ d()->errorPrototype = new ErrorPrototype(exec, d()->objectPrototype, d()->functionPrototype);
+
+ d()->evalErrorPrototype = new NativeErrorPrototype(exec, d()->errorPrototype, "EvalError", "EvalError");
+ d()->rangeErrorPrototype = new NativeErrorPrototype(exec, d()->errorPrototype, "RangeError", "RangeError");
+ d()->referenceErrorPrototype = new NativeErrorPrototype(exec, d()->errorPrototype, "ReferenceError", "ReferenceError");
+ d()->syntaxErrorPrototype = new NativeErrorPrototype(exec, d()->errorPrototype, "SyntaxError", "SyntaxError");
+ d()->typeErrorPrototype = new NativeErrorPrototype(exec, d()->errorPrototype, "TypeError", "TypeError");
+ d()->URIErrorPrototype = new NativeErrorPrototype(exec, d()->errorPrototype, "URIError", "URIError");
+
+ // Constructors
+ d()->objectConstructor = new ObjectObjectImp(exec, d()->objectPrototype, d()->functionPrototype);
+ d()->functionConstructor = new FunctionObjectImp(exec, d()->functionPrototype);
+ d()->arrayConstructor = new ArrayObjectImp(exec, d()->functionPrototype, d()->arrayPrototype);
+ d()->stringConstructor = new StringObjectImp(exec, d()->functionPrototype, d()->stringPrototype);
+ d()->booleanConstructor = new BooleanObjectImp(exec, d()->functionPrototype, d()->booleanPrototype);
+ d()->numberConstructor = new NumberObjectImp(exec, d()->functionPrototype, d()->numberPrototype);
+ d()->dateConstructor = new DateObjectImp(exec, d()->functionPrototype, d()->datePrototype);
+ d()->regExpConstructor = new RegExpObjectImp(exec, d()->functionPrototype, d()->regExpPrototype);
+ d()->errorConstructor = new ErrorObjectImp(exec, d()->functionPrototype, d()->errorPrototype);
+
+ d()->evalErrorConstructor = new NativeErrorImp(exec, d()->functionPrototype, d()->evalErrorPrototype);
+ d()->rangeErrorConstructor = new NativeErrorImp(exec, d()->functionPrototype, d()->rangeErrorPrototype);
+ d()->referenceErrorConstructor = new NativeErrorImp(exec, d()->functionPrototype, d()->referenceErrorPrototype);
+ d()->syntaxErrorConstructor = new NativeErrorImp(exec, d()->functionPrototype, d()->syntaxErrorPrototype);
+ d()->typeErrorConstructor = new NativeErrorImp(exec, d()->functionPrototype, d()->typeErrorPrototype);
+ d()->URIErrorConstructor = new NativeErrorImp(exec, d()->functionPrototype, d()->URIErrorPrototype);
+
+ d()->functionPrototype->putDirect(exec->propertyNames().constructor, d()->functionConstructor, DontEnum);
+
+ d()->objectPrototype->putDirect(exec->propertyNames().constructor, d()->objectConstructor, DontEnum);
+ d()->functionPrototype->putDirect(exec->propertyNames().constructor, d()->functionConstructor, DontEnum);
+ d()->arrayPrototype->putDirect(exec->propertyNames().constructor, d()->arrayConstructor, DontEnum);
+ d()->booleanPrototype->putDirect(exec->propertyNames().constructor, d()->booleanConstructor, DontEnum);
+ d()->stringPrototype->putDirect(exec->propertyNames().constructor, d()->stringConstructor, DontEnum);
+ d()->numberPrototype->putDirect(exec->propertyNames().constructor, d()->numberConstructor, DontEnum);
+ d()->datePrototype->putDirect(exec->propertyNames().constructor, d()->dateConstructor, DontEnum);
+ d()->regExpPrototype->putDirect(exec->propertyNames().constructor, d()->regExpConstructor, DontEnum);
+ d()->errorPrototype->putDirect(exec->propertyNames().constructor, d()->errorConstructor, DontEnum);
+ d()->evalErrorPrototype->putDirect(exec->propertyNames().constructor, d()->evalErrorConstructor, DontEnum);
+ d()->rangeErrorPrototype->putDirect(exec->propertyNames().constructor, d()->rangeErrorConstructor, DontEnum);
+ d()->referenceErrorPrototype->putDirect(exec->propertyNames().constructor, d()->referenceErrorConstructor, DontEnum);
+ d()->syntaxErrorPrototype->putDirect(exec->propertyNames().constructor, d()->syntaxErrorConstructor, DontEnum);
+ d()->typeErrorPrototype->putDirect(exec->propertyNames().constructor, d()->typeErrorConstructor, DontEnum);
+ d()->URIErrorPrototype->putDirect(exec->propertyNames().constructor, d()->URIErrorConstructor, DontEnum);
+
+ // Set global constructors
+
+ // FIXME: These properties could be handled by a static hash table.
+
+ putDirect("Object", d()->objectConstructor, DontEnum);
+ putDirect("Function", d()->functionConstructor, DontEnum);
+ putDirect("Array", d()->arrayConstructor, DontEnum);
+ putDirect("Boolean", d()->booleanConstructor, DontEnum);
+ putDirect("String", d()->stringConstructor, DontEnum);
+ putDirect("Number", d()->numberConstructor, DontEnum);
+ putDirect("Date", d()->dateConstructor, DontEnum);
+ putDirect("RegExp", d()->regExpConstructor, DontEnum);
+ putDirect("Error", d()->errorConstructor, DontEnum);
+ putDirect("EvalError", d()->evalErrorConstructor);
+ putDirect("RangeError", d()->rangeErrorConstructor);
+ putDirect("ReferenceError", d()->referenceErrorConstructor);
+ putDirect("SyntaxError", d()->syntaxErrorConstructor);
+ putDirect("TypeError", d()->typeErrorConstructor);
+ putDirect("URIError", d()->URIErrorConstructor);
+
+ // Set global values.
+
+ putDirect("Math", new MathObjectImp(exec, d()->objectPrototype), DontEnum);
+
+ putDirect("NaN", jsNaN(), DontEnum | DontDelete);
+ putDirect("Infinity", jsNumber(Inf), DontEnum | DontDelete);
+ putDirect("undefined", jsUndefined(), DontEnum | DontDelete);
+
+ // Set global functions.
+
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "eval", globalFuncEval), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 2, "parseInt", globalFuncParseInt), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "parseFloat", globalFuncParseFloat), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "isNaN", globalFuncIsNaN), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "isFinite", globalFuncIsFinite), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "escape", globalFuncEscape), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "unescape", globalFuncUnescape), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "decodeURI", globalFuncDecodeURI), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "decodeURIComponent", globalFuncDecodeURIComponent), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "encodeURI", globalFuncEncodeURI), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "encodeURIComponent", globalFuncEncodeURIComponent), DontEnum);
+#ifndef NDEBUG
+ putDirectFunction(new PrototypeFunction(exec, d()->functionPrototype, 1, "kjsprint", globalFuncKJSPrint), DontEnum);
+#endif
+
+ // Set prototype, and also insert the object prototype at the end of the chain.
+
+ setPrototype(prototype);
+ lastInPrototypeChain(this)->setPrototype(d()->objectPrototype);
+}
+
+void JSGlobalObject::startTimeoutCheck()
+{
+ if (!d()->timeoutCheckCount)
+ resetTimeoutCheck();
+
+ ++d()->timeoutCheckCount;
+}
+
+void JSGlobalObject::stopTimeoutCheck()
+{
+ --d()->timeoutCheckCount;
+}
+
+void JSGlobalObject::resetTimeoutCheck()
+{
+ d()->tickCount = 0;
+ d()->ticksUntilNextTimeoutCheck = initialTickCountThreshold;
+ d()->timeAtLastCheckTimeout = 0;
+ d()->timeExecuting = 0;
+}
+
+bool JSGlobalObject::checkTimeout()
+{
+ d()->tickCount = 0;
+
+ unsigned currentTime = getCurrentTime();
+
+ if (!d()->timeAtLastCheckTimeout) {
+ // Suspicious amount of looping in a script -- start timing it
+ d()->timeAtLastCheckTimeout = currentTime;
+ return false;
+ }
+
+ unsigned timeDiff = currentTime - d()->timeAtLastCheckTimeout;
+
+ if (timeDiff == 0)
+ timeDiff = 1;
+
+ d()->timeExecuting += timeDiff;
+ d()->timeAtLastCheckTimeout = currentTime;
+
+ // Adjust the tick threshold so we get the next checkTimeout call in the interval specified in
+ // preferredScriptCheckTimeInterval
+ d()->ticksUntilNextTimeoutCheck = (unsigned)((float)preferredScriptCheckTimeInterval / timeDiff) * d()->ticksUntilNextTimeoutCheck;
+
+ // 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 (d()->ticksUntilNextTimeoutCheck == 0)
+ d()->ticksUntilNextTimeoutCheck = initialTickCountThreshold;
+
+ if (d()->timeoutTime && d()->timeExecuting > d()->timeoutTime) {
+ if (shouldInterruptScript())
+ return true;
+
+ resetTimeoutCheck();
+ }
+
+ return false;
+}
+
+void JSGlobalObject::saveBuiltins(SavedBuiltins& builtins) const
+{
+ if (!builtins._internal)
+ builtins._internal = new SavedBuiltinsInternal;
+
+ builtins._internal->objectConstructor = d()->objectConstructor;
+ builtins._internal->functionConstructor = d()->functionConstructor;
+ builtins._internal->arrayConstructor = d()->arrayConstructor;
+ builtins._internal->booleanConstructor = d()->booleanConstructor;
+ builtins._internal->stringConstructor = d()->stringConstructor;
+ builtins._internal->numberConstructor = d()->numberConstructor;
+ builtins._internal->dateConstructor = d()->dateConstructor;
+ builtins._internal->regExpConstructor = d()->regExpConstructor;
+ builtins._internal->errorConstructor = d()->errorConstructor;
+ builtins._internal->evalErrorConstructor = d()->evalErrorConstructor;
+ builtins._internal->rangeErrorConstructor = d()->rangeErrorConstructor;
+ builtins._internal->referenceErrorConstructor = d()->referenceErrorConstructor;
+ builtins._internal->syntaxErrorConstructor = d()->syntaxErrorConstructor;
+ builtins._internal->typeErrorConstructor = d()->typeErrorConstructor;
+ builtins._internal->URIErrorConstructor = d()->URIErrorConstructor;
+
+ builtins._internal->objectPrototype = d()->objectPrototype;
+ builtins._internal->functionPrototype = d()->functionPrototype;
+ builtins._internal->arrayPrototype = d()->arrayPrototype;
+ builtins._internal->booleanPrototype = d()->booleanPrototype;
+ builtins._internal->stringPrototype = d()->stringPrototype;
+ builtins._internal->numberPrototype = d()->numberPrototype;
+ builtins._internal->datePrototype = d()->datePrototype;
+ builtins._internal->regExpPrototype = d()->regExpPrototype;
+ builtins._internal->errorPrototype = d()->errorPrototype;
+ builtins._internal->evalErrorPrototype = d()->evalErrorPrototype;
+ builtins._internal->rangeErrorPrototype = d()->rangeErrorPrototype;
+ builtins._internal->referenceErrorPrototype = d()->referenceErrorPrototype;
+ builtins._internal->syntaxErrorPrototype = d()->syntaxErrorPrototype;
+ builtins._internal->typeErrorPrototype = d()->typeErrorPrototype;
+ builtins._internal->URIErrorPrototype = d()->URIErrorPrototype;
+}
+
+void JSGlobalObject::restoreBuiltins(const SavedBuiltins& builtins)
+{
+ if (!builtins._internal)
+ return;
+
+ d()->objectConstructor = builtins._internal->objectConstructor;
+ d()->functionConstructor = builtins._internal->functionConstructor;
+ d()->arrayConstructor = builtins._internal->arrayConstructor;
+ d()->booleanConstructor = builtins._internal->booleanConstructor;
+ d()->stringConstructor = builtins._internal->stringConstructor;
+ d()->numberConstructor = builtins._internal->numberConstructor;
+ d()->dateConstructor = builtins._internal->dateConstructor;
+ d()->regExpConstructor = builtins._internal->regExpConstructor;
+ d()->errorConstructor = builtins._internal->errorConstructor;
+ d()->evalErrorConstructor = builtins._internal->evalErrorConstructor;
+ d()->rangeErrorConstructor = builtins._internal->rangeErrorConstructor;
+ d()->referenceErrorConstructor = builtins._internal->referenceErrorConstructor;
+ d()->syntaxErrorConstructor = builtins._internal->syntaxErrorConstructor;
+ d()->typeErrorConstructor = builtins._internal->typeErrorConstructor;
+ d()->URIErrorConstructor = builtins._internal->URIErrorConstructor;
+
+ d()->objectPrototype = builtins._internal->objectPrototype;
+ d()->functionPrototype = builtins._internal->functionPrototype;
+ d()->arrayPrototype = builtins._internal->arrayPrototype;
+ d()->booleanPrototype = builtins._internal->booleanPrototype;
+ d()->stringPrototype = builtins._internal->stringPrototype;
+ d()->numberPrototype = builtins._internal->numberPrototype;
+ d()->datePrototype = builtins._internal->datePrototype;
+ d()->regExpPrototype = builtins._internal->regExpPrototype;
+ d()->errorPrototype = builtins._internal->errorPrototype;
+ d()->evalErrorPrototype = builtins._internal->evalErrorPrototype;
+ d()->rangeErrorPrototype = builtins._internal->rangeErrorPrototype;
+ d()->referenceErrorPrototype = builtins._internal->referenceErrorPrototype;
+ d()->syntaxErrorPrototype = builtins._internal->syntaxErrorPrototype;
+ d()->typeErrorPrototype = builtins._internal->typeErrorPrototype;
+ d()->URIErrorPrototype = builtins._internal->URIErrorPrototype;
+}
+
+void JSGlobalObject::mark()
+{
+ JSVariableObject::mark();
+
+ markIfNeeded(d()->globalExec.exception());
+
+ markIfNeeded(d()->objectConstructor);
+ markIfNeeded(d()->functionConstructor);
+ markIfNeeded(d()->arrayConstructor);
+ markIfNeeded(d()->booleanConstructor);
+ markIfNeeded(d()->stringConstructor);
+ markIfNeeded(d()->numberConstructor);
+ markIfNeeded(d()->dateConstructor);
+ markIfNeeded(d()->regExpConstructor);
+ markIfNeeded(d()->errorConstructor);
+ markIfNeeded(d()->evalErrorConstructor);
+ markIfNeeded(d()->rangeErrorConstructor);
+ markIfNeeded(d()->referenceErrorConstructor);
+ markIfNeeded(d()->syntaxErrorConstructor);
+ markIfNeeded(d()->typeErrorConstructor);
+ markIfNeeded(d()->URIErrorConstructor);
+
+ markIfNeeded(d()->objectPrototype);
+ markIfNeeded(d()->functionPrototype);
+ markIfNeeded(d()->arrayPrototype);
+ markIfNeeded(d()->booleanPrototype);
+ markIfNeeded(d()->stringPrototype);
+ markIfNeeded(d()->numberPrototype);
+ markIfNeeded(d()->datePrototype);
+ markIfNeeded(d()->regExpPrototype);
+ markIfNeeded(d()->errorPrototype);
+ markIfNeeded(d()->evalErrorPrototype);
+ markIfNeeded(d()->rangeErrorPrototype);
+ markIfNeeded(d()->referenceErrorPrototype);
+ markIfNeeded(d()->syntaxErrorPrototype);
+ markIfNeeded(d()->typeErrorPrototype);
+ markIfNeeded(d()->URIErrorPrototype);
+}
+
+ExecState* JSGlobalObject::globalExec()
+{
+ return &d()->globalExec;
+}
+
+ActivationImp* JSGlobalObject::pushActivation(ExecState* exec)
+{
+ if (d()->activationCount == activationStackNodeSize) {
+ ActivationStackNode* newNode = new ActivationStackNode;
+ newNode->prev = d()->activations;
+ d()->activations = newNode;
+ d()->activationCount = 0;
+ }
+
+ StackActivation* stackEntry = &d()->activations->data[d()->activationCount++];
+ stackEntry->activationStorage.init(exec);
+ return &stackEntry->activationStorage;
+}
+
+inline void JSGlobalObject::checkActivationCount()
+{
+ if (!d()->activationCount) {
+ ActivationStackNode* prev = d()->activations->prev;
+ ASSERT(prev);
+ delete d()->activations;
+ d()->activations = prev;
+ d()->activationCount = activationStackNodeSize;
+ }
+}
+
+void JSGlobalObject::popActivation()
+{
+ checkActivationCount();
+ d()->activations->data[--d()->activationCount].activationDataStorage.localStorage.shrink(0);
+}
+
+void JSGlobalObject::tearOffActivation(ExecState* exec, bool leaveRelic)
+{
+ ActivationImp* oldActivation = exec->activationObject();
+ if (!oldActivation || !oldActivation->isOnStack())
+ return;
+
+ ASSERT(exec->codeType() == FunctionCode);
+ ActivationImp* newActivation = new ActivationImp(*oldActivation->d(), leaveRelic);
+
+ if (!leaveRelic) {
+ checkActivationCount();
+ d()->activationCount--;
+ }
+
+ oldActivation->d()->localStorage.shrink(0);
+
+ exec->setActivationObject(newActivation);
+ exec->setVariableObject(newActivation);
+ exec->setLocalStorage(&newActivation->localStorage());
+ exec->replaceScopeChainTop(newActivation);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/JSGlobalObject.h b/JavaScriptCore/kjs/JSGlobalObject.h
new file mode 100644
index 0000000..d6c055e
--- /dev/null
+++ b/JavaScriptCore/kjs/JSGlobalObject.h
@@ -0,0 +1,255 @@
+// -*- c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_GlobalObject_h
+#define KJS_GlobalObject_h
+
+#include "JSVariableObject.h"
+
+namespace KJS {
+
+ class ActivationImp;
+ class ArrayObjectImp;
+ class ArrayPrototype;
+ class BooleanObjectImp;
+ class BooleanPrototype;
+ class DateObjectImp;
+ class DatePrototype;
+ class Debugger;
+ class ErrorObjectImp;
+ class ErrorPrototype;
+ class EvalError;
+ class EvalErrorPrototype;
+ class FunctionObjectImp;
+ class FunctionPrototype;
+ class JSGlobalObject;
+ class NativeErrorImp;
+ class NativeErrorPrototype;
+ class NumberObjectImp;
+ class NumberPrototype;
+ class ObjectObjectImp;
+ class ObjectPrototype;
+ class RangeError;
+ class RangeErrorPrototype;
+ class ReferenceError;
+ class ReferenceError;
+ class ReferenceErrorPrototype;
+ class RegExpObjectImp;
+ class RegExpPrototype;
+ class RuntimeMethod;
+ class SavedBuiltins;
+ class ScopeChain;
+ class StringObjectImp;
+ class StringPrototype;
+ class SyntaxErrorPrototype;
+ class TypeError;
+ class TypeErrorPrototype;
+ class UriError;
+ class UriErrorPrototype;
+ struct ActivationStackNode;
+
+ class JSGlobalObject : public JSVariableObject {
+ protected:
+ using JSVariableObject::JSVariableObjectData;
+
+ struct JSGlobalObjectData : public JSVariableObjectData {
+ JSGlobalObjectData(JSGlobalObject* globalObject)
+ : JSVariableObjectData(&inlineSymbolTable)
+ , globalExec(globalObject)
+ {
+ }
+
+ JSGlobalObject* next;
+ JSGlobalObject* prev;
+
+ Debugger* debugger;
+
+ GlobalExecState globalExec;
+ int recursion;
+
+ unsigned timeoutTime;
+ unsigned timeAtLastCheckTimeout;
+ unsigned timeExecuting;
+ unsigned timeoutCheckCount;
+ unsigned tickCount;
+ unsigned ticksUntilNextTimeoutCheck;
+
+ ObjectObjectImp* objectConstructor;
+ FunctionObjectImp* functionConstructor;
+ ArrayObjectImp* arrayConstructor;
+ BooleanObjectImp* booleanConstructor;
+ StringObjectImp* stringConstructor;
+ NumberObjectImp* numberConstructor;
+ DateObjectImp* dateConstructor;
+ RegExpObjectImp* regExpConstructor;
+ ErrorObjectImp* errorConstructor;
+ NativeErrorImp* evalErrorConstructor;
+ NativeErrorImp* rangeErrorConstructor;
+ NativeErrorImp* referenceErrorConstructor;
+ NativeErrorImp* syntaxErrorConstructor;
+ NativeErrorImp* typeErrorConstructor;
+ NativeErrorImp* URIErrorConstructor;
+
+ ObjectPrototype* objectPrototype;
+ FunctionPrototype* functionPrototype;
+ ArrayPrototype* arrayPrototype;
+ BooleanPrototype* booleanPrototype;
+ StringPrototype* stringPrototype;
+ NumberPrototype* numberPrototype;
+ DatePrototype* datePrototype;
+ RegExpPrototype* regExpPrototype;
+ ErrorPrototype* errorPrototype;
+ NativeErrorPrototype* evalErrorPrototype;
+ NativeErrorPrototype* rangeErrorPrototype;
+ NativeErrorPrototype* referenceErrorPrototype;
+ NativeErrorPrototype* syntaxErrorPrototype;
+ NativeErrorPrototype* typeErrorPrototype;
+ NativeErrorPrototype* URIErrorPrototype;
+
+ SymbolTable inlineSymbolTable;
+
+ ActivationStackNode* activations;
+ size_t activationCount;
+ };
+
+ public:
+ JSGlobalObject()
+ : JSVariableObject(new JSGlobalObjectData(this))
+ {
+ init();
+ }
+
+ protected:
+ JSGlobalObject(JSValue* proto)
+ : JSVariableObject(proto, new JSGlobalObjectData(this))
+ {
+ init();
+ }
+
+ public:
+ virtual ~JSGlobalObject();
+
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual void put(ExecState*, const Identifier&, JSValue*);
+ virtual void initializeVariable(ExecState*, const Identifier&, JSValue*, unsigned attributes);
+
+ // Linked list of all global objects.
+ static JSGlobalObject* head() { return s_head; }
+ JSGlobalObject* next() { return d()->next; }
+
+ // Resets the global object to contain only built-in properties, sets
+ // the global object's prototype to "prototype," then adds the
+ // default object prototype to the tail of the global object's
+ // prototype chain.
+ void reset(JSValue* prototype);
+
+ // The following accessors return pristine values, even if a script
+ // replaces the global object's associated property.
+
+ ObjectObjectImp* objectConstructor() const { return d()->objectConstructor; }
+ FunctionObjectImp* functionConstructor() const { return d()->functionConstructor; }
+ ArrayObjectImp* arrayConstructor() const { return d()->arrayConstructor; }
+ BooleanObjectImp* booleanConstructor() const { return d()->booleanConstructor; }
+ StringObjectImp* stringConstructor() const{ return d()->stringConstructor; }
+ NumberObjectImp* numberConstructor() const{ return d()->numberConstructor; }
+ DateObjectImp* dateConstructor() const{ return d()->dateConstructor; }
+ RegExpObjectImp* regExpConstructor() const { return d()->regExpConstructor; }
+ ErrorObjectImp* errorConstructor() const { return d()->errorConstructor; }
+ NativeErrorImp* evalErrorConstructor() const { return d()->evalErrorConstructor; }
+ NativeErrorImp* rangeErrorConstructor() const { return d()->rangeErrorConstructor; }
+ NativeErrorImp* referenceErrorConstructor() const { return d()->referenceErrorConstructor; }
+ NativeErrorImp* syntaxErrorConstructor() const { return d()->syntaxErrorConstructor; }
+ NativeErrorImp* typeErrorConstructor() const { return d()->typeErrorConstructor; }
+ NativeErrorImp* URIErrorConstructor() const { return d()->URIErrorConstructor; }
+
+ ObjectPrototype* objectPrototype() const { return d()->objectPrototype; }
+ FunctionPrototype* functionPrototype() const { return d()->functionPrototype; }
+ ArrayPrototype* arrayPrototype() const { return d()->arrayPrototype; }
+ BooleanPrototype* booleanPrototype() const { return d()->booleanPrototype; }
+ StringPrototype* stringPrototype() const { return d()->stringPrototype; }
+ NumberPrototype* numberPrototype() const { return d()->numberPrototype; }
+ DatePrototype* datePrototype() const { return d()->datePrototype; }
+ RegExpPrototype* regExpPrototype() const { return d()->regExpPrototype; }
+ ErrorPrototype* errorPrototype() const { return d()->errorPrototype; }
+ NativeErrorPrototype* evalErrorPrototype() const { return d()->evalErrorPrototype; }
+ NativeErrorPrototype* rangeErrorPrototype() const { return d()->rangeErrorPrototype; }
+ NativeErrorPrototype* referenceErrorPrototype() const { return d()->referenceErrorPrototype; }
+ NativeErrorPrototype* syntaxErrorPrototype() const { return d()->syntaxErrorPrototype; }
+ NativeErrorPrototype* typeErrorPrototype() const { return d()->typeErrorPrototype; }
+ NativeErrorPrototype* URIErrorPrototype() const { return d()->URIErrorPrototype; }
+
+ void saveBuiltins(SavedBuiltins&) const;
+ void restoreBuiltins(const SavedBuiltins&);
+
+ void setTimeoutTime(unsigned timeoutTime) { d()->timeoutTime = timeoutTime; }
+ void startTimeoutCheck();
+ void stopTimeoutCheck();
+ bool timedOut();
+
+ Debugger* debugger() const { return d()->debugger; }
+ void setDebugger(Debugger* debugger) { d()->debugger = debugger; }
+
+ int recursion() { return d()->recursion; }
+ void incRecursion() { ++d()->recursion; }
+ void decRecursion() { --d()->recursion; }
+
+ virtual void mark();
+
+ virtual bool isGlobalObject() const { return true; }
+
+ virtual ExecState* globalExec();
+
+ virtual bool shouldInterruptScript() const { return true; }
+
+ virtual bool allowsAccessFrom(const JSGlobalObject*) const { return true; }
+
+ ActivationImp* pushActivation(ExecState*);
+ void popActivation();
+ void tearOffActivation(ExecState*, bool markAsRelic = false);
+
+ private:
+ void init();
+
+ JSGlobalObjectData* d() const { return static_cast<JSGlobalObjectData*>(JSVariableObject::d); }
+
+ bool checkTimeout();
+ void resetTimeoutCheck();
+
+ void deleteActivationStack();
+ void checkActivationCount();
+
+ static JSGlobalObject* s_head;
+ };
+
+ inline bool JSGlobalObject::timedOut()
+ {
+ d()->tickCount++;
+
+ if (d()->tickCount != d()->ticksUntilNextTimeoutCheck)
+ return false;
+
+ return checkTimeout();
+ }
+
+} // namespace KJS
+
+#endif // KJS_GlobalObject_h
diff --git a/JavaScriptCore/kjs/JSImmediate.cpp b/JavaScriptCore/kjs/JSImmediate.cpp
new file mode 100644
index 0000000..ded8ccb
--- /dev/null
+++ b/JavaScriptCore/kjs/JSImmediate.cpp
@@ -0,0 +1,82 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2003-2006 Apple Computer, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "JSImmediate.h"
+
+#include "JSGlobalObject.h"
+#include "bool_object.h"
+#include "number_object.h"
+#include "object.h"
+
+namespace KJS {
+
+JSObject *JSImmediate::toObject(const JSValue *v, ExecState *exec)
+{
+ ASSERT(isImmediate(v));
+ if (v == jsNull())
+ return throwError(exec, TypeError, "Null value");
+ else if (v == jsUndefined())
+ return throwError(exec, TypeError, "Undefined value");
+ else if (isBoolean(v)) {
+ List args;
+ args.append(const_cast<JSValue *>(v));
+ return exec->lexicalGlobalObject()->booleanConstructor()->construct(exec, args);
+ } else {
+ ASSERT(isNumber(v));
+ List args;
+ args.append(const_cast<JSValue *>(v));
+ return exec->lexicalGlobalObject()->numberConstructor()->construct(exec, args);
+ }
+}
+
+UString JSImmediate::toString(const JSValue *v)
+{
+ ASSERT(isImmediate(v));
+
+ if (v == jsNull())
+ return "null";
+ else if (v == jsUndefined())
+ return "undefined";
+ else if (v == jsBoolean(true))
+ return "true";
+ else if (v == jsBoolean(false))
+ return "false";
+ else {
+ ASSERT(isNumber(v));
+ double d = toDouble(v);
+ if (d == 0.0) // +0.0 or -0.0
+ return "0";
+ return UString::from(d);
+ }
+}
+
+JSType JSImmediate::type(const JSValue *v)
+{
+ ASSERT(isImmediate(v));
+
+ uintptr_t tag = getTag(v);
+ if (tag == UndefinedType)
+ return v == jsUndefined() ? UndefinedType : NullType;
+ return static_cast<JSType>(tag);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/JSImmediate.h b/JavaScriptCore/kjs/JSImmediate.h
new file mode 100644
index 0000000..bc0cb16
--- /dev/null
+++ b/JavaScriptCore/kjs/JSImmediate.h
@@ -0,0 +1,278 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@webkit.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_JS_IMMEDIATE_H
+#define KJS_JS_IMMEDIATE_H
+
+#include "JSType.h"
+#include <wtf/Assertions.h>
+#include <wtf/AlwaysInline.h>
+#include <wtf/MathExtras.h>
+#include <limits>
+#include <stdarg.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+namespace KJS {
+
+class ExecState;
+class JSObject;
+class JSValue;
+class UString;
+
+/*
+ * A JSValue* is either a pointer to a cell (a heap-allocated object) or an immediate (a type-tagged
+ * signed int masquerading as a pointer). The low two bits in a JSValue* are available
+ * for type tagging because allocator alignment guarantees they will be 00 in cell pointers.
+ *
+ * For example, on a 32 bit system:
+ *
+ * JSCell*: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX 00
+ * [ high 30 bits: pointer address ] [ low 2 bits -- always 0 ]
+ *
+ * JSImmediate: XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX TT
+ * [ high 30 bits: signed int ] [ low 2 bits -- type tag ]
+ *
+ * The bit "payload" (the high 30 bits) is a 30 bit signed int for immediate numbers, a flag to distinguish true/false
+ * and undefined/null.
+ *
+ * Notice that the JSType value of NullType is 4, which requires 3 bits to encode. Since we only have 2 bits
+ * available for type tagging, we tag the null immediate with UndefinedType, and JSImmediate::type() has
+ * to sort them out.
+ */
+
+class JSImmediate {
+public:
+ static ALWAYS_INLINE bool isImmediate(const JSValue* v)
+ {
+ return getTag(v) != 0;
+ }
+
+ static ALWAYS_INLINE bool isNumber(const JSValue* v)
+ {
+ return (getTag(v) == NumberType);
+ }
+
+ static ALWAYS_INLINE bool isBoolean(const JSValue* v)
+ {
+ return (getTag(v) == BooleanType);
+ }
+
+ // Since we have room for only 3 unique tags, null and undefined have to share.
+ static ALWAYS_INLINE bool isUndefinedOrNull(const JSValue* v)
+ {
+ return (getTag(v) == UndefinedType);
+ }
+
+ static JSValue* from(char);
+ static JSValue* from(signed char);
+ static JSValue* from(unsigned char);
+ static JSValue* from(short);
+ static JSValue* from(unsigned short);
+ static JSValue* from(int);
+ static JSValue* from(unsigned);
+ static JSValue* from(long);
+ static JSValue* from(unsigned long);
+ static JSValue* from(long long);
+ static JSValue* from(unsigned long long);
+ static JSValue* from(double);
+
+ static ALWAYS_INLINE bool areBothImmediateNumbers(const JSValue* v1, const JSValue* v2)
+ {
+ return (reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2) & TagMask) == NumberType;
+ }
+
+ static ALWAYS_INLINE JSValue* andImmediateNumbers(const JSValue* v1, const JSValue* v2)
+ {
+ ASSERT(areBothImmediateNumbers(v1, v2));
+ return reinterpret_cast<JSValue*>(reinterpret_cast<uintptr_t>(v1) & reinterpret_cast<uintptr_t>(v2));
+ }
+
+ static double toDouble(const JSValue*);
+ static bool toBoolean(const JSValue*);
+ static JSObject* toObject(const JSValue*, ExecState*);
+ static UString toString(const JSValue*);
+ static JSType type(const JSValue*);
+
+ static bool getUInt32(const JSValue*, uint32_t&);
+ static bool getTruncatedInt32(const JSValue*, int32_t&);
+ static bool getTruncatedUInt32(const JSValue*, uint32_t&);
+
+ static int32_t getTruncatedInt32(const JSValue*);
+
+ static JSValue* trueImmediate();
+ static JSValue* falseImmediate();
+ static JSValue* undefinedImmediate();
+ static JSValue* nullImmediate();
+
+private:
+ static const uintptr_t TagMask = 3; // type tags are 2 bits long
+
+ // Immediate values are restricted to a 30 bit signed value.
+ static const int minImmediateInt = -(1 << 29);
+ static const int maxImmediateInt = (1 << 29) - 1;
+ static const unsigned maxImmediateUInt = maxImmediateInt;
+
+ static ALWAYS_INLINE JSValue* tag(uintptr_t bits, uintptr_t tag)
+ {
+ return reinterpret_cast<JSValue*>(bits | tag);
+ }
+
+ static ALWAYS_INLINE uintptr_t unTag(const JSValue* v)
+ {
+ return reinterpret_cast<uintptr_t>(v) & ~TagMask;
+ }
+
+ static ALWAYS_INLINE uintptr_t getTag(const JSValue* v)
+ {
+ return reinterpret_cast<uintptr_t>(v) & TagMask;
+ }
+};
+
+ALWAYS_INLINE JSValue* JSImmediate::trueImmediate() { return tag(1 << 2, BooleanType); }
+ALWAYS_INLINE JSValue* JSImmediate::falseImmediate() { return tag(0, BooleanType); }
+ALWAYS_INLINE JSValue* JSImmediate::undefinedImmediate() { return tag(1 << 2, UndefinedType); }
+ALWAYS_INLINE JSValue* JSImmediate::nullImmediate() { return tag(0, UndefinedType); }
+
+ALWAYS_INLINE bool JSImmediate::toBoolean(const JSValue* v)
+{
+ ASSERT(isImmediate(v));
+ uintptr_t bits = unTag(v);
+ return (bits != 0) & (JSImmediate::getTag(v) != UndefinedType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(char i)
+{
+ return tag(i << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(signed char i)
+{
+ return tag(i << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(unsigned char i)
+{
+ return tag(i << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(short i)
+{
+ return tag(i << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(unsigned short i)
+{
+ return tag(i << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(int i)
+{
+ if ((i < minImmediateInt) | (i > maxImmediateInt))
+ return 0;
+ return tag(i << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(unsigned i)
+{
+ if (i > maxImmediateUInt)
+ return 0;
+ return tag(i << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(long i)
+{
+ if ((i < minImmediateInt) | (i > maxImmediateInt))
+ return 0;
+ return tag(i << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long i)
+{
+ if (i > maxImmediateUInt)
+ return 0;
+ return tag(i << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(long long i)
+{
+ if ((i < minImmediateInt) | (i > maxImmediateInt))
+ return 0;
+ return tag(static_cast<uintptr_t>(i) << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(unsigned long long i)
+{
+ if (i > maxImmediateUInt)
+ return 0;
+ return tag(static_cast<uintptr_t>(i) << 2, NumberType);
+}
+
+ALWAYS_INLINE JSValue* JSImmediate::from(double d)
+{
+ const int intVal = static_cast<int>(d);
+
+ if ((intVal < minImmediateInt) | (intVal > maxImmediateInt))
+ return 0;
+
+ // Check for data loss from conversion to int.
+ if ((intVal != d) || (!intVal && signbit(d)))
+ return 0;
+
+ return tag(intVal << 2, NumberType);
+}
+
+ALWAYS_INLINE int32_t JSImmediate::getTruncatedInt32(const JSValue* v)
+{
+ ASSERT(isNumber(v));
+ return static_cast<int32_t>(unTag(v)) >> 2;
+}
+
+ALWAYS_INLINE double JSImmediate::toDouble(const JSValue* v)
+{
+ ASSERT(isImmediate(v));
+ const int32_t i = static_cast<int32_t>(unTag(v)) >> 2;
+ if (JSImmediate::getTag(v) == UndefinedType && i)
+ return std::numeric_limits<double>::quiet_NaN();
+ return i;
+}
+
+ALWAYS_INLINE bool JSImmediate::getUInt32(const JSValue* v, uint32_t& i)
+{
+ const int32_t si = static_cast<int32_t>(unTag(v)) >> 2;
+ i = si;
+ return isNumber(v) & (si >= 0);
+}
+
+ALWAYS_INLINE bool JSImmediate::getTruncatedInt32(const JSValue* v, int32_t& i)
+{
+ i = static_cast<int32_t>(unTag(v)) >> 2;
+ return isNumber(v);
+}
+
+ALWAYS_INLINE bool JSImmediate::getTruncatedUInt32(const JSValue* v, uint32_t& i)
+{
+ return getUInt32(v, i);
+}
+
+} // namespace KJS
+
+#endif
diff --git a/JavaScriptCore/kjs/JSLock.cpp b/JavaScriptCore/kjs/JSLock.cpp
new file mode 100644
index 0000000..9d51ca9
--- /dev/null
+++ b/JavaScriptCore/kjs/JSLock.cpp
@@ -0,0 +1,143 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2005 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+ *
+ */
+
+#include "config.h"
+#include "JSLock.h"
+
+#include "collector.h"
+#if USE(MULTIPLE_THREADS)
+#include <pthread.h>
+#endif
+
+namespace KJS {
+
+#if USE(MULTIPLE_THREADS)
+
+// Acquire this mutex before accessing lock-related data.
+static pthread_mutex_t JSMutex = PTHREAD_MUTEX_INITIALIZER;
+
+// Thread-specific key that tells whether a thread holds the JSMutex.
+pthread_key_t didLockJSMutex;
+
+// Lock nesting count.
+static int JSLockCount;
+
+static void createDidLockJSMutex()
+{
+ pthread_key_create(&didLockJSMutex, 0);
+}
+pthread_once_t createDidLockJSMutexOnce = PTHREAD_ONCE_INIT;
+
+void JSLock::lock()
+{
+ pthread_once(&createDidLockJSMutexOnce, createDidLockJSMutex);
+
+ if (!pthread_getspecific(didLockJSMutex)) {
+ int result;
+ result = pthread_mutex_lock(&JSMutex);
+ ASSERT(!result);
+ pthread_setspecific(didLockJSMutex, &didLockJSMutex);
+ }
+ ++JSLockCount;
+}
+
+void JSLock::unlock()
+{
+ ASSERT(JSLockCount);
+ ASSERT(!!pthread_getspecific(didLockJSMutex));
+
+ --JSLockCount;
+ if (!JSLockCount) {
+ pthread_setspecific(didLockJSMutex, 0);
+ int result;
+ result = pthread_mutex_unlock(&JSMutex);
+ ASSERT(!result);
+ }
+}
+
+bool JSLock::currentThreadIsHoldingLock()
+{
+ pthread_once(&createDidLockJSMutexOnce, createDidLockJSMutex);
+ return !!pthread_getspecific(didLockJSMutex);
+}
+
+void JSLock::registerThread()
+{
+ Collector::registerThread();
+}
+
+JSLock::DropAllLocks::DropAllLocks()
+ : m_lockCount(0)
+{
+ pthread_once(&createDidLockJSMutexOnce, createDidLockJSMutex);
+
+ m_lockCount = !!pthread_getspecific(didLockJSMutex) ? JSLock::lockCount() : 0;
+ for (int i = 0; i < m_lockCount; i++)
+ JSLock::unlock();
+}
+
+JSLock::DropAllLocks::~DropAllLocks()
+{
+ for (int i = 0; i < m_lockCount; i++)
+ JSLock::lock();
+ m_lockCount = 0;
+}
+
+#else
+
+// If threading support is off, set the lock count to a constant value of 1 so assertions
+// that the lock is held don't fail
+const int JSLockCount = 1;
+
+bool JSLock::currentThreadIsHoldingLock()
+{
+ return true;
+}
+
+void JSLock::lock()
+{
+}
+
+void JSLock::unlock()
+{
+}
+
+void JSLock::registerThread()
+{
+}
+
+JSLock::DropAllLocks::DropAllLocks()
+{
+}
+
+JSLock::DropAllLocks::~DropAllLocks()
+{
+}
+
+#endif // USE(MULTIPLE_THREADS)
+
+int JSLock::lockCount()
+{
+ return JSLockCount;
+}
+
+}
diff --git a/JavaScriptCore/kjs/JSLock.h b/JavaScriptCore/kjs/JSLock.h
new file mode 100644
index 0000000..f6cda5d
--- /dev/null
+++ b/JavaScriptCore/kjs/JSLock.h
@@ -0,0 +1,81 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2005 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_JSLock_h
+#define KJS_JSLock_h
+
+#include <wtf/Assertions.h>
+#include <wtf/Noncopyable.h>
+
+namespace KJS {
+
+ // 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.
+
+ class JSLock : Noncopyable {
+ public:
+ JSLock()
+ {
+ lock();
+ registerThread();
+ }
+
+ ~JSLock()
+ {
+ unlock();
+ }
+
+ static void lock();
+ static void unlock();
+ static int lockCount();
+ static bool currentThreadIsHoldingLock();
+
+ static void registerThread();
+
+ class DropAllLocks : Noncopyable {
+ public:
+ DropAllLocks();
+ ~DropAllLocks();
+
+ private:
+ int m_lockCount;
+ };
+ };
+
+} // namespace
+
+#endif // KJS_JSLock_h
diff --git a/JavaScriptCore/kjs/JSType.h b/JavaScriptCore/kjs/JSType.h
new file mode 100644
index 0000000..1c9418c
--- /dev/null
+++ b/JavaScriptCore/kjs/JSType.h
@@ -0,0 +1,43 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2006 Apple Computer, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_JSTYPE_H
+#define KJS_JSTYPE_H
+
+namespace KJS {
+
+/**
+ * Primitive types
+ */
+enum JSType {
+ UnspecifiedType = 0,
+ UndefinedType = 1,
+ BooleanType = 2,
+ NumberType = 3,
+ NullType = 4,
+ StringType = 5,
+ ObjectType = 6,
+ GetterSetterType = 7
+};
+
+} // namespace KJS
+
+#endif
diff --git a/JavaScriptCore/kjs/JSVariableObject.cpp b/JavaScriptCore/kjs/JSVariableObject.cpp
new file mode 100644
index 0000000..76d563d
--- /dev/null
+++ b/JavaScriptCore/kjs/JSVariableObject.cpp
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2007, 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+#include "JSVariableObject.h"
+
+#include "PropertyNameArray.h"
+#include "property_map.h"
+
+namespace KJS {
+
+UString::Rep* IdentifierRepHashTraits::nullRepPtr = &UString::Rep::null; // Didn't want to make a whole source file for just this.
+
+void JSVariableObject::saveLocalStorage(SavedProperties& p) const
+{
+ ASSERT(d->symbolTable);
+ ASSERT(static_cast<size_t>(d->symbolTable->size()) == d->localStorage.size());
+
+ unsigned count = d->symbolTable->size();
+
+ p.properties.clear();
+ p.count = count;
+
+ if (!count)
+ return;
+
+ p.properties.set(new SavedProperty[count]);
+
+ SymbolTable::const_iterator end = d->symbolTable->end();
+ for (SymbolTable::const_iterator it = d->symbolTable->begin(); it != end; ++it) {
+ size_t i = it->second;
+ const LocalStorageEntry& entry = d->localStorage[i];
+ p.properties[i].init(it->first.get(), entry.value, entry.attributes);
+ }
+}
+
+void JSVariableObject::restoreLocalStorage(const SavedProperties& p)
+{
+ unsigned count = p.count;
+ d->symbolTable->clear();
+ d->localStorage.resize(count);
+ SavedProperty* property = p.properties.get();
+ for (size_t i = 0; i < count; ++i, ++property) {
+ ASSERT(!d->symbolTable->contains(property->name()));
+ LocalStorageEntry& entry = d->localStorage[i];
+ d->symbolTable->set(property->name(), i);
+ entry.value = property->value();
+ entry.attributes = property->attributes();
+ }
+}
+
+bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propertyName)
+{
+ if (symbolTable().contains(propertyName.ustring().rep()))
+ return false;
+
+ return JSObject::deleteProperty(exec, propertyName);
+}
+
+void JSVariableObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+{
+ SymbolTable::const_iterator::Keys end = symbolTable().end().keys();
+ for (SymbolTable::const_iterator::Keys it = symbolTable().begin().keys(); it != end; ++it)
+ propertyNames.add(Identifier(it->get()));
+
+ JSObject::getPropertyNames(exec, propertyNames);
+}
+
+void JSVariableObject::mark()
+{
+ JSObject::mark();
+
+ size_t size = d->localStorage.size();
+ for (size_t i = 0; i < size; ++i) {
+ JSValue* value = d->localStorage[i].value;
+ if (!value->marked())
+ value->mark();
+ }
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/JSVariableObject.h b/JavaScriptCore/kjs/JSVariableObject.h
new file mode 100644
index 0000000..e22e9c6
--- /dev/null
+++ b/JavaScriptCore/kjs/JSVariableObject.h
@@ -0,0 +1,135 @@
+/*
+ * 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 "LocalStorage.h"
+#include "SymbolTable.h"
+#include "object.h"
+
+namespace KJS {
+
+ class JSVariableObject : public JSObject {
+ public:
+ SymbolTable& symbolTable() { return *d->symbolTable; }
+ LocalStorage& localStorage() { return d->localStorage; }
+
+ void saveLocalStorage(SavedProperties&) const;
+ void restoreLocalStorage(const SavedProperties&);
+
+ virtual void initializeVariable(ExecState*, const Identifier&, JSValue*, unsigned attributes) = 0;
+
+ virtual bool deleteProperty(ExecState*, const Identifier&);
+ virtual void getPropertyNames(ExecState*, PropertyNameArray&);
+
+ virtual void mark();
+
+ protected:
+ // Subclasses of JSVariableObject can subclass this struct to add data
+ // without increasing their own size (since there's a hard limit on the
+ // size of a JSCell).
+ struct JSVariableObjectData {
+ JSVariableObjectData() { }
+ JSVariableObjectData(SymbolTable* s)
+ : symbolTable(s) // Subclass owns this pointer.
+ {
+ }
+
+ LocalStorage localStorage; // Storage for variables in the symbol table.
+ SymbolTable* symbolTable; // Maps name -> index in localStorage.
+ };
+
+ JSVariableObject() { }
+
+ JSVariableObject(JSVariableObjectData* data)
+ : d(data) // Subclass owns this pointer.
+ {
+ }
+
+ JSVariableObject(JSValue* proto, JSVariableObjectData* data)
+ : JSObject(proto)
+ , d(data) // Subclass owns this pointer.
+ {
+ }
+
+ bool symbolTableGet(const Identifier&, PropertySlot&);
+ bool symbolTablePut(const Identifier&, JSValue*);
+ bool symbolTableInitializeVariable(const Identifier&, JSValue*, unsigned attributes);
+
+ JSVariableObjectData* d;
+ };
+
+ inline bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertySlot& slot)
+ {
+ size_t index = symbolTable().get(propertyName.ustring().rep());
+ if (index != missingSymbolMarker()) {
+#ifndef NDEBUG
+ // During initialization, the variable object needs to advertise that it has certain
+ // properties, even if they're not ready for access yet. This check verifies that
+ // no one tries to access such a property.
+
+ // In a release build, we optimize this check away and just return an invalid pointer.
+ // There's no harm in an invalid pointer, since no one dereferences it.
+ if (index >= d->localStorage.size()) {
+ slot.setUngettable(this);
+ return true;
+ }
+#endif
+ slot.setValueSlot(this, &d->localStorage[index].value);
+ return true;
+ }
+ return false;
+ }
+
+ inline bool JSVariableObject::symbolTablePut(const Identifier& propertyName, JSValue* value)
+ {
+ size_t index = symbolTable().get(propertyName.ustring().rep());
+ if (index == missingSymbolMarker())
+ return false;
+ LocalStorageEntry& entry = d->localStorage[index];
+ if (entry.attributes & ReadOnly)
+ return true;
+ entry.value = value;
+ return true;
+ }
+
+ inline bool JSVariableObject::symbolTableInitializeVariable(const Identifier& propertyName, JSValue* value, unsigned attributes)
+ {
+ size_t index = symbolTable().get(propertyName.ustring().rep());
+ if (index == missingSymbolMarker())
+ return false;
+ LocalStorageEntry& entry = d->localStorage[index];
+ entry.value = value;
+ entry.attributes = attributes;
+ return true;
+ }
+
+} // namespace KJS
+
+#endif // JSVariableObject_h
diff --git a/JavaScriptCore/kjs/JSWrapperObject.cpp b/JavaScriptCore/kjs/JSWrapperObject.cpp
new file mode 100644
index 0000000..dd161f7
--- /dev/null
+++ b/JavaScriptCore/kjs/JSWrapperObject.cpp
@@ -0,0 +1,34 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 2006 Maks Orlovich
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "JSWrapperObject.h"
+
+namespace KJS {
+
+void JSWrapperObject::mark()
+{
+ JSObject::mark();
+ if (m_internalValue && !m_internalValue->marked())
+ m_internalValue->mark();
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/JSWrapperObject.h b/JavaScriptCore/kjs/JSWrapperObject.h
new file mode 100644
index 0000000..0a06c9f
--- /dev/null
+++ b/JavaScriptCore/kjs/JSWrapperObject.h
@@ -0,0 +1,84 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2006 Maks Orlovich
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_JSWrapperObject_h
+#define KJS_JSWrapperObject_h
+
+#include "object.h"
+
+namespace KJS {
+
+ /**
+ This class is used as a base for classes such as String,
+ Number, Boolean and Date which which are wrappers for primitive
+ types. These classes stores the internal value, which is the
+ actual value represented by the wrapper objects.
+ */
+ class JSWrapperObject : public JSObject {
+ public:
+ JSWrapperObject(JSValue* proto);
+
+ /**
+ * Returns the internal value of the object. This is used for objects such
+ * as String and Boolean which are wrappers for native types. The interal
+ * value is the actual value represented by the wrapper objects.
+ *
+ * @see ECMA 8.6.2
+ * @return The internal value of the object
+ */
+ JSValue* internalValue() const;
+
+ /**
+ * Sets the internal value of the object
+ *
+ * @see internalValue()
+ *
+ * @param v The new internal value
+ */
+ void setInternalValue(JSValue* v);
+
+ virtual void mark();
+
+ private:
+ JSValue* m_internalValue;
+ };
+
+ inline JSWrapperObject::JSWrapperObject(JSValue* proto)
+ : JSObject(proto)
+ , m_internalValue(0)
+ {
+ }
+
+ inline JSValue* JSWrapperObject::internalValue() const
+ {
+ return m_internalValue;
+ }
+
+ inline void JSWrapperObject::setInternalValue(JSValue* v)
+ {
+ ASSERT(v);
+ m_internalValue = v;
+ }
+
+} // namespace KJS
+
+#endif // KJS_JSWrapperObject_h
diff --git a/JavaScriptCore/kjs/LabelStack.h b/JavaScriptCore/kjs/LabelStack.h
new file mode 100644
index 0000000..375edf1
--- /dev/null
+++ b/JavaScriptCore/kjs/LabelStack.h
@@ -0,0 +1,84 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_LABEL_STACK_H
+#define KJS_LABEL_STACK_H
+
+#include "identifier.h"
+#include <wtf/Noncopyable.h>
+
+namespace KJS {
+ /**
+ * @short The "label set" in Ecma-262 spec
+ */
+ class LabelStack : Noncopyable {
+ public:
+ LabelStack()
+ : tos(0)
+ {
+ }
+ ~LabelStack();
+
+ /**
+ * If id is not empty and is not in the stack already, puts it on top of
+ * the stack and returns true, otherwise returns false
+ */
+ bool push(const Identifier &id);
+ /**
+ * Is the id in the stack?
+ */
+ bool contains(const Identifier &id) const;
+ /**
+ * Removes from the stack the last pushed id (what else?)
+ */
+ void pop();
+
+ private:
+ struct StackElem {
+ Identifier id;
+ StackElem *prev;
+ };
+
+ StackElem *tos;
+ };
+
+inline LabelStack::~LabelStack()
+{
+ StackElem *prev;
+ for (StackElem *e = tos; e; e = prev) {
+ prev = e->prev;
+ delete e;
+ }
+}
+
+inline void LabelStack::pop()
+{
+ if (StackElem *e = tos) {
+ tos = e->prev;
+ delete e;
+ }
+}
+
+}
+
+#endif // KJS_LABEL_STACK_H
diff --git a/JavaScriptCore/kjs/LocalStorage.h b/JavaScriptCore/kjs/LocalStorage.h
new file mode 100644
index 0000000..87a54bb
--- /dev/null
+++ b/JavaScriptCore/kjs/LocalStorage.h
@@ -0,0 +1,56 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * 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 KJS_LOCAL_STORAGE_H
+#define KJS_LOCAL_STORAGE_H
+
+#include <wtf/Forward.h>
+#include <wtf/VectorTraits.h>
+
+namespace KJS {
+ class JSValue;
+
+ struct LocalStorageEntry {
+ LocalStorageEntry()
+ {
+ }
+
+ LocalStorageEntry(JSValue* v, unsigned a)
+ : value(v)
+ , attributes(a)
+ {
+ }
+
+ JSValue* value;
+ unsigned attributes;
+ };
+
+ typedef Vector<LocalStorageEntry, 32> LocalStorage;
+}
+
+namespace WTF {
+ template<> struct VectorTraits<KJS::LocalStorageEntry> : VectorTraitsBase<true, KJS::LocalStorageEntry> { };
+}
+
+#endif // KJS_LOCAL_STORAGE_H
diff --git a/JavaScriptCore/kjs/NodeInfo.h b/JavaScriptCore/kjs/NodeInfo.h
new file mode 100644
index 0000000..60637f2
--- /dev/null
+++ b/JavaScriptCore/kjs/NodeInfo.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef NodeInfo_h
+#define NodeInfo_h
+
+#include "nodes.h"
+#include "Parser.h"
+
+namespace KJS {
+
+template <typename T> struct NodeInfo {
+ T m_node;
+ ParserRefCountedData<DeclarationStacks::VarStack>* m_varDeclarations;
+ ParserRefCountedData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+};
+
+typedef NodeInfo<StatementNode*> StatementNodeInfo;
+typedef NodeInfo<CaseBlockNode*> CaseBlockNodeInfo;
+typedef NodeInfo<CaseClauseNode*> CaseClauseNodeInfo;
+typedef NodeInfo<SourceElements*> SourceElementsInfo;
+typedef NodeInfo<ClauseList> ClauseListInfo;
+typedef NodeInfo<ExpressionNode*> VarDeclListInfo;
+typedef NodeInfo<ConstDeclList> ConstDeclListInfo;
+
+} // namespace KJS
+
+#endif // NodeInfo_h
diff --git a/JavaScriptCore/kjs/Parser.cpp b/JavaScriptCore/kjs/Parser.cpp
new file mode 100644
index 0000000..c6d7265
--- /dev/null
+++ b/JavaScriptCore/kjs/Parser.cpp
@@ -0,0 +1,91 @@
+// -*- c-basic-offset: 4 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2006, 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 "Parser.h"
+
+#include "lexer.h"
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+
+extern int kjsyyparse();
+
+namespace KJS {
+
+Parser::Parser()
+ : m_sourceId(0)
+{
+}
+
+void Parser::parse(int startingLineNumber,
+ const UChar* code, unsigned length,
+ int* sourceId, int* errLine, UString* errMsg)
+{
+ ASSERT(!m_sourceElements);
+
+ if (errLine)
+ *errLine = -1;
+ if (errMsg)
+ *errMsg = 0;
+
+ Lexer& lexer = KJS::lexer();
+
+ lexer.setCode(startingLineNumber, code, length);
+ m_sourceId++;
+ if (sourceId)
+ *sourceId = m_sourceId;
+
+ int parseError = kjsyyparse();
+ bool lexError = lexer.sawError();
+ lexer.clear();
+
+ ParserRefCounted::deleteNewObjects();
+
+ if (parseError || lexError) {
+ if (errLine)
+ *errLine = lexer.lineNo();
+ if (errMsg)
+ *errMsg = "Parse error";
+ m_sourceElements.clear();
+ }
+}
+
+void Parser::didFinishParsing(SourceElements* sourceElements, ParserRefCountedData<DeclarationStacks::VarStack>* varStack,
+ ParserRefCountedData<DeclarationStacks::FunctionStack>* funcStack, int lastLine)
+{
+ m_sourceElements = sourceElements ? sourceElements : new SourceElements;
+ m_varDeclarations = varStack;
+ m_funcDeclarations = funcStack;
+ m_lastLine = lastLine;
+}
+
+Parser& parser()
+{
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ static Parser& staticParser = *new Parser;
+ return staticParser;
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/Parser.h b/JavaScriptCore/kjs/Parser.h
new file mode 100644
index 0000000..92548fe
--- /dev/null
+++ b/JavaScriptCore/kjs/Parser.h
@@ -0,0 +1,99 @@
+// -*- c-basic-offset: 4 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2006, 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.
+ *
+ */
+
+#ifndef Parser_h
+#define Parser_h
+
+#include <wtf/Forward.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/RefPtr.h>
+#include "nodes.h"
+
+namespace KJS {
+
+ class FunctionBodyNode;
+ class ProgramNode;
+ class UString;
+
+ struct UChar;
+
+ template <typename T> struct ParserRefCountedData : ParserRefCounted {
+ T data;
+ };
+
+ class Parser : Noncopyable {
+ public:
+ template <class ParsedNode>
+ PassRefPtr<ParsedNode> parse(const UString& sourceURL, int startingLineNumber,
+ const UChar* code, unsigned length,
+ int* sourceId = 0, int* errLine = 0, UString* errMsg = 0);
+
+ UString sourceURL() const { return m_sourceURL; }
+ int sourceId() const { return m_sourceId; }
+
+ void didFinishParsing(SourceElements*, ParserRefCountedData<DeclarationStacks::VarStack>*,
+ ParserRefCountedData<DeclarationStacks::FunctionStack>*, int lastLine);
+
+ private:
+ friend Parser& parser();
+
+ Parser(); // Use parser() instead.
+ void parse(int startingLineNumber, const UChar* code, unsigned length,
+ int* sourceId, int* errLine, UString* errMsg);
+
+ UString m_sourceURL;
+ int m_sourceId;
+ RefPtr<SourceElements> m_sourceElements;
+ RefPtr<ParserRefCountedData<DeclarationStacks::VarStack> > m_varDeclarations;
+ RefPtr<ParserRefCountedData<DeclarationStacks::FunctionStack> > m_funcDeclarations;
+ int m_lastLine;
+ };
+
+ Parser& parser(); // Returns the singleton JavaScript parser.
+
+ template <class ParsedNode>
+ PassRefPtr<ParsedNode> Parser::parse(const UString& sourceURL, int startingLineNumber,
+ const UChar* code, unsigned length,
+ int* sourceId, int* errLine, UString* errMsg)
+ {
+ m_sourceURL = sourceURL;
+ parse(startingLineNumber, code, length, sourceId, errLine, errMsg);
+ if (!m_sourceElements) {
+ m_sourceURL = UString();
+ return 0;
+ }
+ RefPtr<ParsedNode> node = ParsedNode::create(m_sourceElements.release().get(),
+ m_varDeclarations ? &m_varDeclarations->data : 0,
+ m_funcDeclarations ? &m_funcDeclarations->data : 0);
+ m_varDeclarations = 0;
+ m_funcDeclarations = 0;
+ m_sourceURL = UString();
+ node->setLoc(startingLineNumber, m_lastLine);
+ return node.release();
+ }
+
+} // namespace KJS
+
+#endif // Parser_h
diff --git a/JavaScriptCore/kjs/PropertyNameArray.cpp b/JavaScriptCore/kjs/PropertyNameArray.cpp
new file mode 100644
index 0000000..45dda3a
--- /dev/null
+++ b/JavaScriptCore/kjs/PropertyNameArray.cpp
@@ -0,0 +1,43 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2006 Apple Computer, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "PropertyNameArray.h"
+
+namespace KJS {
+
+void PropertyNameArray::add(const Identifier& ident)
+{
+ if (!m_set.add(ident.ustring().rep()).second)
+ return;
+
+ m_vector.append(ident);
+}
+
+void PropertyNameArray::swap(PropertyNameArray& other)
+{
+ m_vector.swap(other.m_vector);
+ m_set.swap(other.m_set);
+}
+
+
+} // namespace KJS
+
diff --git a/JavaScriptCore/kjs/PropertyNameArray.h b/JavaScriptCore/kjs/PropertyNameArray.h
new file mode 100644
index 0000000..b702d21
--- /dev/null
+++ b/JavaScriptCore/kjs/PropertyNameArray.h
@@ -0,0 +1,56 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2006 Apple Computer, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_PROPERTY_NAME_ARRAY_H
+#define KJS_PROPERTY_NAME_ARRAY_H
+
+#include "identifier.h"
+
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+
+namespace KJS {
+
+ class PropertyNameArray {
+ public:
+ typedef Identifier ValueType;
+ typedef Vector<Identifier>::const_iterator const_iterator;
+
+ void add(const Identifier&);
+ const_iterator begin() const { return m_vector.begin(); }
+ const_iterator end() const { return m_vector.end(); }
+ size_t size() const { return m_vector.size(); }
+
+ Identifier& operator[](unsigned i) { return m_vector[i]; }
+ const Identifier& operator[](unsigned i) const { return m_vector[i]; }
+
+ void swap(PropertyNameArray&);
+ private:
+ typedef HashSet<UString::Rep*, PtrHash<UString::Rep*> > IdentifierSet;
+ IdentifierSet m_set;
+ Vector<Identifier> m_vector;
+ };
+
+
+} // namespace KJS
+
+
+#endif // KJS_PROPERTY_NAME_ARRAY_H
diff --git a/JavaScriptCore/kjs/SavedBuiltins.h b/JavaScriptCore/kjs/SavedBuiltins.h
new file mode 100644
index 0000000..9901e41
--- /dev/null
+++ b/JavaScriptCore/kjs/SavedBuiltins.h
@@ -0,0 +1,94 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef SavedBuiltins_H
+#define SavedBuiltins_H
+
+#include "protect.h"
+#include "object_object.h"
+#include "string_object.h"
+#include "error_object.h"
+#include "regexp_object.h"
+#include "array_object.h"
+#include "bool_object.h"
+#include "date_object.h"
+#include "number_object.h"
+#include "math_object.h"
+
+namespace KJS {
+
+struct SavedBuiltinsInternal {
+ ProtectedPtr<ObjectObjectImp> objectConstructor;
+ ProtectedPtr<FunctionObjectImp> functionConstructor;
+ ProtectedPtr<ArrayObjectImp> arrayConstructor;
+ ProtectedPtr<BooleanObjectImp> booleanConstructor;
+ ProtectedPtr<StringObjectImp> stringConstructor;
+ ProtectedPtr<NumberObjectImp> numberConstructor;
+ ProtectedPtr<DateObjectImp> dateConstructor;
+ ProtectedPtr<RegExpObjectImp> regExpConstructor;
+ ProtectedPtr<ErrorObjectImp> errorConstructor;
+ ProtectedPtr<NativeErrorImp> evalErrorConstructor;
+ ProtectedPtr<NativeErrorImp> rangeErrorConstructor;
+ ProtectedPtr<NativeErrorImp> referenceErrorConstructor;
+ ProtectedPtr<NativeErrorImp> syntaxErrorConstructor;
+ ProtectedPtr<NativeErrorImp> typeErrorConstructor;
+ ProtectedPtr<NativeErrorImp> URIErrorConstructor;
+
+ ProtectedPtr<ObjectPrototype> objectPrototype;
+ ProtectedPtr<FunctionPrototype> functionPrototype;
+ ProtectedPtr<ArrayPrototype> arrayPrototype;
+ ProtectedPtr<BooleanPrototype> booleanPrototype;
+ ProtectedPtr<StringPrototype> stringPrototype;
+ ProtectedPtr<NumberPrototype> numberPrototype;
+ ProtectedPtr<DatePrototype> datePrototype;
+ ProtectedPtr<RegExpPrototype> regExpPrototype;
+ ProtectedPtr<ErrorPrototype> errorPrototype;
+ ProtectedPtr<NativeErrorPrototype> evalErrorPrototype;
+ ProtectedPtr<NativeErrorPrototype> rangeErrorPrototype;
+ ProtectedPtr<NativeErrorPrototype> referenceErrorPrototype;
+ ProtectedPtr<NativeErrorPrototype> syntaxErrorPrototype;
+ ProtectedPtr<NativeErrorPrototype> typeErrorPrototype;
+ ProtectedPtr<NativeErrorPrototype> URIErrorPrototype;
+};
+
+class SavedBuiltins {
+ friend class JSGlobalObject;
+public:
+ SavedBuiltins()
+ : _internal(0)
+ {
+ }
+
+ ~SavedBuiltins()
+ {
+ delete _internal;
+ }
+
+private:
+ SavedBuiltinsInternal* _internal;
+};
+
+} // namespace
+
+#endif // SavedBuiltins_H
diff --git a/JavaScriptCore/kjs/SymbolTable.h b/JavaScriptCore/kjs/SymbolTable.h
new file mode 100644
index 0000000..1c2b2e8
--- /dev/null
+++ b/JavaScriptCore/kjs/SymbolTable.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must 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 "ustring.h"
+#include <wtf/AlwaysInline.h>
+
+namespace KJS {
+
+ struct IdentifierRepHash {
+ static unsigned hash(const RefPtr<UString::Rep>& key) { return key->computedHash(); }
+ static bool equal(const RefPtr<UString::Rep>& a, const RefPtr<UString::Rep>& b) { return a == b; }
+ static const bool safeToCompareToEmptyOrDeleted = true;
+ };
+
+ struct IdentifierRepHashTraits : HashTraits<RefPtr<UString::Rep> > {
+ static const RefPtr<UString::Rep>& deletedValue()
+ {
+ return *reinterpret_cast<RefPtr<UString::Rep>*>(&nullRepPtr);
+ }
+
+ private:
+ static UString::Rep* nullRepPtr;
+ };
+
+ static ALWAYS_INLINE size_t missingSymbolMarker() { return std::numeric_limits<size_t>::max(); }
+
+ struct SymbolTableIndexHashTraits {
+ typedef size_t TraitType;
+ typedef SymbolTableIndexHashTraits StorageTraits;
+ static size_t emptyValue() { return missingSymbolMarker(); }
+ static const bool emptyValueIsZero = false;
+ static const bool needsDestruction = false;
+ static const bool needsRef = false;
+ };
+
+ typedef HashMap<RefPtr<UString::Rep>, size_t, IdentifierRepHash, IdentifierRepHashTraits, SymbolTableIndexHashTraits> SymbolTable;
+
+} // namespace KJS
+
+#endif // SymbolTable_h
diff --git a/JavaScriptCore/kjs/array_instance.cpp b/JavaScriptCore/kjs/array_instance.cpp
new file mode 100644
index 0000000..1118f40
--- /dev/null
+++ b/JavaScriptCore/kjs/array_instance.cpp
@@ -0,0 +1,605 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "array_instance.h"
+
+#include "JSGlobalObject.h"
+#include "PropertyNameArray.h"
+#include <wtf/Assertions.h>
+
+using std::min;
+
+namespace KJS {
+
+typedef HashMap<unsigned, JSValue*> SparseArrayValueMap;
+
+struct ArrayStorage {
+ unsigned m_numValuesInVector;
+ SparseArrayValueMap* m_sparseValueMap;
+ JSValue* m_vector[1];
+};
+
+// 0xFFFFFFFF is a bit weird -- is not an array index even though it's an integer
+static const unsigned maxArrayIndex = 0xFFFFFFFEU;
+
+// Our policy for when to use a vector and when to use a sparse map.
+// For all array indices under sparseArrayCutoff, we always use a vector.
+// When indices greater than sparseArrayCutoff 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 sparseArrayCutoff = 10000;
+static const unsigned minDensityMultiplier = 8;
+
+static const unsigned copyingSortCutoff = 50000;
+
+const ClassInfo ArrayInstance::info = {"Array", 0, 0};
+
+static inline size_t storageSize(unsigned vectorLength)
+{
+ return sizeof(ArrayStorage) - sizeof(JSValue*) + vectorLength * sizeof(JSValue*);
+}
+
+static inline unsigned increasedVectorLength(unsigned newLength)
+{
+ return (newLength * 3 + 1) / 2;
+}
+
+static inline bool isDenseEnoughForVector(unsigned length, unsigned numValues)
+{
+ return length / minDensityMultiplier <= numValues;
+}
+
+ArrayInstance::ArrayInstance(JSObject* prototype, unsigned initialLength)
+ : JSObject(prototype)
+{
+ unsigned initialCapacity = min(initialLength, sparseArrayCutoff);
+
+ m_length = initialLength;
+ m_vectorLength = initialCapacity;
+ m_storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity)));
+
+ Collector::reportExtraMemoryCost(initialCapacity * sizeof(JSValue*));
+}
+
+ArrayInstance::ArrayInstance(JSObject* prototype, const List& list)
+ : JSObject(prototype)
+{
+ unsigned length = list.size();
+
+ m_length = length;
+ m_vectorLength = length;
+
+ ArrayStorage* storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(length)));
+
+ storage->m_numValuesInVector = length;
+ storage->m_sparseValueMap = 0;
+
+ size_t i = 0;
+ List::const_iterator end = list.end();
+ for (List::const_iterator it = list.begin(); it != end; ++it, ++i)
+ storage->m_vector[i] = *it;
+
+ m_storage = storage;
+
+ // When the array is created non-empty, its cells are filled, so it's really no worse than
+ // a property map. Therefore don't report extra memory cost.
+}
+
+ArrayInstance::~ArrayInstance()
+{
+ delete m_storage->m_sparseValueMap;
+ fastFree(m_storage);
+}
+
+JSValue* ArrayInstance::getItem(unsigned i) const
+{
+ ASSERT(i <= maxArrayIndex);
+
+ ArrayStorage* storage = m_storage;
+
+ if (i < m_vectorLength) {
+ JSValue* value = storage->m_vector[i];
+ return value ? value : jsUndefined();
+ }
+
+ SparseArrayValueMap* map = storage->m_sparseValueMap;
+ if (!map)
+ return jsUndefined();
+
+ JSValue* value = map->get(i);
+ return value ? value : jsUndefined();
+}
+
+JSValue* ArrayInstance::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
+{
+ return jsNumber(static_cast<ArrayInstance*>(slot.slotBase())->m_length);
+}
+
+ALWAYS_INLINE bool ArrayInstance::inlineGetOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
+{
+ ArrayStorage* storage = m_storage;
+
+ if (i >= m_length) {
+ if (i > maxArrayIndex)
+ return getOwnPropertySlot(exec, Identifier::from(i), slot);
+ return false;
+ }
+
+ if (i < m_vectorLength) {
+ JSValue*& valueSlot = storage->m_vector[i];
+ if (valueSlot) {
+ slot.setValueSlot(this, &valueSlot);
+ return true;
+ }
+ } else if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ if (i >= sparseArrayCutoff) {
+ SparseArrayValueMap::iterator it = map->find(i);
+ if (it != map->end()) {
+ slot.setValueSlot(this, &it->second);
+ return true;
+ }
+ }
+ }
+
+ return false;
+}
+
+bool ArrayInstance::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (propertyName == exec->propertyNames().length) {
+ slot.setCustom(this, lengthGetter);
+ return true;
+ }
+
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ if (isArrayIndex)
+ return inlineGetOwnPropertySlot(exec, i, slot);
+
+ return JSObject::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+bool ArrayInstance::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot)
+{
+ return inlineGetOwnPropertySlot(exec, i, slot);
+}
+
+// ECMA 15.4.5.1
+void ArrayInstance::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
+{
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ if (isArrayIndex) {
+ put(exec, i, value);
+ return;
+ }
+
+ if (propertyName == exec->propertyNames().length) {
+ unsigned newLength = value->toUInt32(exec);
+ if (value->toNumber(exec) != static_cast<double>(newLength)) {
+ throwError(exec, RangeError, "Invalid array length.");
+ return;
+ }
+ setLength(newLength);
+ return;
+ }
+
+ JSObject::put(exec, propertyName, value);
+}
+
+void ArrayInstance::put(ExecState* exec, unsigned i, JSValue* value)
+{
+ if (i > maxArrayIndex) {
+ put(exec, Identifier::from(i), value);
+ return;
+ }
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned length = m_length;
+ if (i >= length) {
+ length = i + 1;
+ m_length = length;
+ }
+
+ if (i < m_vectorLength) {
+ JSValue*& valueSlot = storage->m_vector[i];
+ storage->m_numValuesInVector += !valueSlot;
+ valueSlot = value;
+ return;
+ }
+
+ if (i < sparseArrayCutoff) {
+ increaseVectorLength(i + 1);
+ storage = m_storage;
+ ++storage->m_numValuesInVector;
+ storage->m_vector[i] = value;
+ return;
+ }
+
+ SparseArrayValueMap* map = storage->m_sparseValueMap;
+ if (!map || map->isEmpty()) {
+ if (isDenseEnoughForVector(i + 1, storage->m_numValuesInVector + 1)) {
+ increaseVectorLength(i + 1);
+ storage = m_storage;
+ ++storage->m_numValuesInVector;
+ storage->m_vector[i] = value;
+ return;
+ }
+ if (!map) {
+ map = new SparseArrayValueMap;
+ storage->m_sparseValueMap = map;
+ }
+ map->set(i, value);
+ return;
+ }
+
+ unsigned newNumValuesInVector = storage->m_numValuesInVector + 1;
+ if (!isDenseEnoughForVector(i + 1, newNumValuesInVector)) {
+ map->set(i, value);
+ return;
+ }
+
+ unsigned newVectorLength = increasedVectorLength(i + 1);
+ for (unsigned j = m_vectorLength; j < newVectorLength; ++j)
+ newNumValuesInVector += map->contains(j);
+ newNumValuesInVector -= map->contains(i);
+ if (isDenseEnoughForVector(newVectorLength, newNumValuesInVector)) {
+ unsigned proposedNewNumValuesInVector = newNumValuesInVector;
+ while (true) {
+ unsigned proposedNewVectorLength = increasedVectorLength(newVectorLength + 1);
+ for (unsigned j = newVectorLength; j < proposedNewVectorLength; ++j)
+ proposedNewNumValuesInVector += map->contains(j);
+ if (!isDenseEnoughForVector(proposedNewVectorLength, proposedNewNumValuesInVector))
+ break;
+ newVectorLength = proposedNewVectorLength;
+ newNumValuesInVector = proposedNewNumValuesInVector;
+ }
+ }
+
+ storage = static_cast<ArrayStorage*>(fastRealloc(storage, storageSize(newVectorLength)));
+
+ unsigned vectorLength = m_vectorLength;
+ if (newNumValuesInVector == storage->m_numValuesInVector + 1) {
+ for (unsigned j = vectorLength; j < newVectorLength; ++j)
+ storage->m_vector[j] = 0;
+ map->remove(i);
+ } else {
+ for (unsigned j = vectorLength; j < newVectorLength; ++j)
+ storage->m_vector[j] = map->take(j);
+ }
+
+ storage->m_vector[i] = value;
+
+ m_vectorLength = newVectorLength;
+ storage->m_numValuesInVector = newNumValuesInVector;
+}
+
+bool ArrayInstance::deleteProperty(ExecState* exec, const Identifier& propertyName)
+{
+ bool isArrayIndex;
+ unsigned i = propertyName.toArrayIndex(&isArrayIndex);
+ if (isArrayIndex)
+ return deleteProperty(exec, i);
+
+ if (propertyName == exec->propertyNames().length)
+ return false;
+
+ return JSObject::deleteProperty(exec, propertyName);
+}
+
+bool ArrayInstance::deleteProperty(ExecState* exec, unsigned i)
+{
+ ArrayStorage* storage = m_storage;
+
+ if (i < m_vectorLength) {
+ JSValue*& valueSlot = storage->m_vector[i];
+ bool hadValue = valueSlot;
+ valueSlot = 0;
+ storage->m_numValuesInVector -= hadValue;
+ return hadValue;
+ }
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ if (i >= sparseArrayCutoff) {
+ SparseArrayValueMap::iterator it = map->find(i);
+ if (it != map->end()) {
+ map->remove(it);
+ return true;
+ }
+ }
+ }
+
+ if (i > maxArrayIndex)
+ return deleteProperty(exec, Identifier::from(i));
+
+ return false;
+}
+
+void ArrayInstance::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+{
+ // FIXME: Filling PropertyNameArray with an identifier for every integer
+ // is incredibly inefficient for large arrays. We need a different approach.
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned usedVectorLength = min(m_length, m_vectorLength);
+ for (unsigned i = 0; i < usedVectorLength; ++i) {
+ if (storage->m_vector[i])
+ propertyNames.add(Identifier::from(i));
+ }
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ SparseArrayValueMap::iterator end = map->end();
+ for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
+ propertyNames.add(Identifier::from(it->first));
+ }
+
+ JSObject::getPropertyNames(exec, propertyNames);
+}
+
+void ArrayInstance::increaseVectorLength(unsigned newLength)
+{
+ ArrayStorage* storage = m_storage;
+
+ unsigned vectorLength = m_vectorLength;
+ ASSERT(newLength > vectorLength);
+ unsigned newVectorLength = increasedVectorLength(newLength);
+
+ storage = static_cast<ArrayStorage*>(fastRealloc(storage, storageSize(newVectorLength)));
+ m_vectorLength = newVectorLength;
+
+ for (unsigned i = vectorLength; i < newVectorLength; ++i)
+ storage->m_vector[i] = 0;
+
+ m_storage = storage;
+}
+
+void ArrayInstance::setLength(unsigned newLength)
+{
+ ArrayStorage* storage = m_storage;
+
+ unsigned length = m_length;
+
+ if (newLength < length) {
+ unsigned usedVectorLength = min(length, m_vectorLength);
+ for (unsigned i = newLength; i < usedVectorLength; ++i) {
+ JSValue*& valueSlot = storage->m_vector[i];
+ bool hadValue = valueSlot;
+ valueSlot = 0;
+ storage->m_numValuesInVector -= hadValue;
+ }
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ SparseArrayValueMap copy = *map;
+ SparseArrayValueMap::iterator end = copy.end();
+ for (SparseArrayValueMap::iterator it = copy.begin(); it != end; ++it) {
+ if (it->first >= newLength)
+ map->remove(it->first);
+ }
+ if (map->isEmpty()) {
+ delete map;
+ storage->m_sparseValueMap = 0;
+ }
+ }
+ }
+
+ m_length = newLength;
+}
+
+void ArrayInstance::mark()
+{
+ JSObject::mark();
+
+ ArrayStorage* storage = m_storage;
+
+ unsigned usedVectorLength = min(m_length, m_vectorLength);
+ for (unsigned i = 0; i < usedVectorLength; ++i) {
+ JSValue* value = storage->m_vector[i];
+ if (value && !value->marked())
+ value->mark();
+ }
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ SparseArrayValueMap::iterator end = map->end();
+ for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) {
+ JSValue* value = it->second;
+ if (!value->marked())
+ value->mark();
+ }
+ }
+}
+
+static int compareByStringPairForQSort(const void* a, const void* b)
+{
+ const std::pair<JSValue*, UString>* va = static_cast<const std::pair<JSValue*, UString>*>(a);
+ const std::pair<JSValue*, UString>* vb = static_cast<const std::pair<JSValue*, UString>*>(b);
+ return compare(va->second, vb->second);
+}
+
+static ExecState* execForCompareByStringForQSort = 0;
+static int compareByStringForQSort(const void* a, const void* b)
+{
+ ExecState* exec = execForCompareByStringForQSort;
+
+ JSValue* va = *static_cast<JSValue* const*>(a);
+ JSValue* vb = *static_cast<JSValue* const*>(b);
+ ASSERT(!va->isUndefined());
+ ASSERT(!vb->isUndefined());
+
+ return compare(va->toString(exec), vb->toString(exec));
+}
+
+void ArrayInstance::sort(ExecState* exec)
+{
+ unsigned lengthNotIncludingUndefined = compactForSorting();
+
+ if (lengthNotIncludingUndefined < copyingSortCutoff) {
+ // 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. For large arrays, we fall back to a qsort on the JavaScriptValues to avoid creating copies.
+
+ Vector<std::pair<JSValue*, UString> > values(lengthNotIncludingUndefined);
+ for (size_t i = 0; i < lengthNotIncludingUndefined; i++) {
+ JSValue* value = m_storage->m_vector[i];
+ ASSERT(!value->isUndefined());
+ values[i].first = value;
+ values[i].second = value->toString(exec);
+ }
+
+ // 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(std::pair<JSValue*, UString>), compareByStringPairForQSort);
+#else
+ qsort(values.begin(), values.size(), sizeof(std::pair<JSValue*, UString>), compareByStringPairForQSort);
+#endif
+ for (size_t i = 0; i < lengthNotIncludingUndefined; i++)
+ m_storage->m_vector[i] = values[i].first;
+ return;
+ }
+
+ ExecState* oldExec = execForCompareByStringForQSort;
+ execForCompareByStringForQSort = exec;
+ qsort(m_storage->m_vector, lengthNotIncludingUndefined, sizeof(JSValue*), compareByStringForQSort);
+ execForCompareByStringForQSort = oldExec;
+}
+
+struct CompareWithCompareFunctionArguments {
+ CompareWithCompareFunctionArguments(ExecState *e, JSObject *cf)
+ : exec(e)
+ , compareFunction(cf)
+ , globalObject(e->dynamicGlobalObject())
+ {
+ }
+
+ ExecState *exec;
+ JSObject *compareFunction;
+ List arguments;
+ JSGlobalObject* globalObject;
+};
+
+static CompareWithCompareFunctionArguments* compareWithCompareFunctionArguments = 0;
+
+static int compareWithCompareFunctionForQSort(const void* a, const void* b)
+{
+ CompareWithCompareFunctionArguments *args = compareWithCompareFunctionArguments;
+
+ JSValue* va = *static_cast<JSValue* const*>(a);
+ JSValue* vb = *static_cast<JSValue* const*>(b);
+ ASSERT(!va->isUndefined());
+ ASSERT(!vb->isUndefined());
+
+ args->arguments.clear();
+ args->arguments.append(va);
+ args->arguments.append(vb);
+ double compareResult = args->compareFunction->call
+ (args->exec, args->globalObject, args->arguments)->toNumber(args->exec);
+ return compareResult < 0 ? -1 : compareResult > 0 ? 1 : 0;
+}
+
+void ArrayInstance::sort(ExecState* exec, JSObject* compareFunction)
+{
+ size_t lengthNotIncludingUndefined = compactForSorting();
+
+ CompareWithCompareFunctionArguments* oldArgs = compareWithCompareFunctionArguments;
+ CompareWithCompareFunctionArguments args(exec, compareFunction);
+ compareWithCompareFunctionArguments = &args;
+
+#if HAVE(MERGESORT)
+ // Because mergesort usually does fewer compares, it is faster than qsort here.
+ // However, because it requires extra copies of the storage buffer, don't use it for very
+ // large arrays.
+
+ // FIXME: A tree sort using a perfectly balanced tree (e.g. an AVL tree) could do an even
+ // better job of minimizing compares.
+
+ if (lengthNotIncludingUndefined < copyingSortCutoff) {
+ // During the sort, we could do a garbage collect, and it's important to still
+ // have references to every object in the array for ArrayInstance::mark.
+ // The mergesort algorithm does not guarantee this, so we sort a copy rather
+ // than the original.
+ size_t size = storageSize(m_vectorLength);
+ ArrayStorage* copy = static_cast<ArrayStorage*>(fastMalloc(size));
+ memcpy(copy, m_storage, size);
+ mergesort(copy->m_vector, lengthNotIncludingUndefined, sizeof(JSValue*), compareWithCompareFunctionForQSort);
+ fastFree(m_storage);
+ m_storage = copy;
+ compareWithCompareFunctionArguments = oldArgs;
+ return;
+ }
+#endif
+
+ qsort(m_storage->m_vector, lengthNotIncludingUndefined, sizeof(JSValue*), compareWithCompareFunctionForQSort);
+ compareWithCompareFunctionArguments = oldArgs;
+}
+
+unsigned ArrayInstance::compactForSorting()
+{
+ ArrayStorage* storage = m_storage;
+
+ unsigned usedVectorLength = min(m_length, m_vectorLength);
+
+ unsigned numDefined = 0;
+ unsigned numUndefined = 0;
+
+ for (; numDefined < usedVectorLength; ++numDefined) {
+ JSValue* v = storage->m_vector[numDefined];
+ if (!v || v->isUndefined())
+ break;
+ }
+ for (unsigned i = numDefined; i < usedVectorLength; ++i) {
+ if (JSValue* v = storage->m_vector[i]) {
+ if (v->isUndefined())
+ ++numUndefined;
+ else
+ storage->m_vector[numDefined++] = v;
+ }
+ }
+
+ unsigned newUsedVectorLength = numDefined + numUndefined;
+
+ if (SparseArrayValueMap* map = storage->m_sparseValueMap) {
+ newUsedVectorLength += map->size();
+ if (newUsedVectorLength > m_vectorLength) {
+ increaseVectorLength(newUsedVectorLength);
+ storage = m_storage;
+ }
+
+ SparseArrayValueMap::iterator end = map->end();
+ for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it)
+ storage->m_vector[numDefined++] = it->second;
+
+ delete map;
+ storage->m_sparseValueMap = 0;
+ }
+
+ for (unsigned i = numDefined; i < newUsedVectorLength; ++i)
+ storage->m_vector[i] = jsUndefined();
+ for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i)
+ storage->m_vector[i] = 0;
+
+ return numDefined;
+}
+
+}
diff --git a/JavaScriptCore/kjs/array_instance.h b/JavaScriptCore/kjs/array_instance.h
new file mode 100644
index 0000000..d7efdde
--- /dev/null
+++ b/JavaScriptCore/kjs/array_instance.h
@@ -0,0 +1,72 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * 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 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 ARRAY_INSTANCE_H
+#define ARRAY_INSTANCE_H
+
+#include "object.h"
+
+namespace KJS {
+
+ struct ArrayStorage;
+
+ class ArrayInstance : public JSObject {
+ public:
+ ArrayInstance(JSObject* prototype, unsigned initialLength);
+ ArrayInstance(JSObject* prototype, const List& initialValues);
+ ~ArrayInstance();
+
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&);
+ virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
+ virtual void put(ExecState*, const Identifier& propertyName, JSValue*);
+ virtual void put(ExecState*, unsigned propertyName, JSValue*);
+ virtual bool deleteProperty(ExecState *, const Identifier& propertyName);
+ virtual bool deleteProperty(ExecState *, unsigned propertyName);
+ virtual void getPropertyNames(ExecState*, PropertyNameArray&);
+
+ virtual void mark();
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+
+ unsigned getLength() const { return m_length; }
+ JSValue* getItem(unsigned) const;
+
+ void sort(ExecState*);
+ void sort(ExecState*, JSObject* compareFunction);
+
+ private:
+ static JSValue* lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
+ bool inlineGetOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
+
+ void setLength(unsigned);
+ void increaseVectorLength(unsigned newLength);
+
+ unsigned compactForSorting();
+
+ unsigned m_length;
+ unsigned m_vectorLength;
+ ArrayStorage* m_storage;
+ };
+
+} // namespace KJS
+
+#endif
diff --git a/JavaScriptCore/kjs/array_object.cpp b/JavaScriptCore/kjs/array_object.cpp
new file mode 100644
index 0000000..48b0855
--- /dev/null
+++ b/JavaScriptCore/kjs/array_object.cpp
@@ -0,0 +1,760 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2003 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2006 Alexey Proskuryakov (ap@nypop.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301
+ * USA
+ *
+ */
+
+#include "config.h"
+#include "array_object.h"
+#include "array_object.lut.h"
+
+#include "error_object.h"
+#include "lookup.h"
+#include "operations.h"
+#include <stdio.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashSet.h>
+
+#include <algorithm> // for std::min
+
+namespace KJS {
+
+// ------------------------------ ArrayPrototype ----------------------------
+
+const ClassInfo ArrayPrototype::info = {"Array", &ArrayInstance::info, &arrayTable};
+
+/* Source for array_object.lut.h
+@begin arrayTable 16
+ toString arrayProtoFuncToString DontEnum|Function 0
+ toLocaleString arrayProtoFuncToLocaleString DontEnum|Function 0
+ concat arrayProtoFuncConcat DontEnum|Function 1
+ join arrayProtoFuncJoin DontEnum|Function 1
+ pop arrayProtoFuncPop DontEnum|Function 0
+ push arrayProtoFuncPush DontEnum|Function 1
+ reverse arrayProtoFuncReverse DontEnum|Function 0
+ shift arrayProtoFuncShift DontEnum|Function 0
+ slice arrayProtoFuncSlice DontEnum|Function 2
+ sort arrayProtoFuncSort DontEnum|Function 1
+ splice arrayProtoFuncSplice DontEnum|Function 2
+ unshift arrayProtoFuncUnShift DontEnum|Function 1
+ every arrayProtoFuncEvery DontEnum|Function 1
+ forEach arrayProtoFuncForEach DontEnum|Function 1
+ some arrayProtoFuncSome DontEnum|Function 1
+ indexOf arrayProtoFuncIndexOf DontEnum|Function 1
+ lastIndexOf arrayProtoFuncLastIndexOf DontEnum|Function 1
+ filter arrayProtoFuncFilter DontEnum|Function 1
+ map arrayProtoFuncMap DontEnum|Function 1
+@end
+*/
+
+// ECMA 15.4.4
+ArrayPrototype::ArrayPrototype(ExecState*, ObjectPrototype* objProto)
+ : ArrayInstance(objProto, 0)
+{
+}
+
+bool ArrayPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<ArrayInstance>(exec, &arrayTable, this, propertyName, slot);
+}
+
+
+// ------------------------------ Array Functions ----------------------------
+
+// Helper function
+static JSValue* getProperty(ExecState* exec, JSObject* obj, unsigned index)
+{
+ PropertySlot slot;
+ if (!obj->getPropertySlot(exec, index, slot))
+ return 0;
+ return slot.getValue(exec, obj, index);
+}
+
+JSValue* arrayProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&ArrayInstance::info))
+ return throwError(exec, TypeError);
+
+ static HashSet<JSObject*> visitedElems;
+ static const UString* empty = new UString("");
+ static const UString* comma = new UString(",");
+ bool alreadyVisited = !visitedElems.add(thisObj).second;
+ if (alreadyVisited)
+ return jsString(*empty);
+ UString separator = *comma;
+ UString str = *empty;
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ for (unsigned k = 0; k < length; k++) {
+ if (k >= 1)
+ str += separator;
+ if (str.isNull()) {
+ JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+ exec->setException(error);
+ break;
+ }
+
+ JSValue* element = thisObj->get(exec, k);
+ if (element->isUndefinedOrNull())
+ continue;
+
+ str += element->toString(exec);
+
+ if (str.isNull()) {
+ JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+ exec->setException(error);
+ }
+
+ if (exec->hadException())
+ break;
+ }
+ visitedElems.remove(thisObj);
+ return jsString(str);
+}
+
+JSValue* arrayProtoFuncToLocaleString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&ArrayInstance::info))
+ return throwError(exec, TypeError);
+
+ static HashSet<JSObject*> visitedElems;
+ static const UString* empty = new UString("");
+ static const UString* comma = new UString(",");
+ bool alreadyVisited = !visitedElems.add(thisObj).second;
+ if (alreadyVisited)
+ return jsString(*empty);
+ UString separator = *comma;
+ UString str = *empty;
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ for (unsigned k = 0; k < length; k++) {
+ if (k >= 1)
+ str += separator;
+ if (str.isNull()) {
+ JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+ exec->setException(error);
+ break;
+ }
+
+ JSValue* element = thisObj->get(exec, k);
+ if (element->isUndefinedOrNull())
+ continue;
+
+ JSObject* o = element->toObject(exec);
+ JSValue* conversionFunction = o->get(exec, exec->propertyNames().toLocaleString);
+ if (conversionFunction->isObject() && static_cast<JSObject*>(conversionFunction)->implementsCall())
+ str += static_cast<JSObject*>(conversionFunction)->call(exec, o, exec->emptyList())->toString(exec);
+ else
+ str += element->toString(exec);
+
+ if (str.isNull()) {
+ JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+ exec->setException(error);
+ }
+
+ if (exec->hadException())
+ break;
+ }
+ visitedElems.remove(thisObj);
+ return jsString(str);
+}
+
+JSValue* arrayProtoFuncJoin(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ static HashSet<JSObject*> visitedElems;
+ static const UString* empty = new UString("");
+ static const UString* comma = new UString(",");
+ bool alreadyVisited = !visitedElems.add(thisObj).second;
+ if (alreadyVisited)
+ return jsString(*empty);
+ UString separator = *comma;
+ UString str = *empty;
+
+ if (!args[0]->isUndefined())
+ separator = args[0]->toString(exec);
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ for (unsigned k = 0; k < length; k++) {
+ if (k >= 1)
+ str += separator;
+ if (str.isNull()) {
+ JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+ exec->setException(error);
+ break;
+ }
+
+ JSValue* element = thisObj->get(exec, k);
+ if (element->isUndefinedOrNull())
+ continue;
+
+ str += element->toString(exec);
+
+ if (str.isNull()) {
+ JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+ exec->setException(error);
+ }
+
+ if (exec->hadException())
+ break;
+ }
+ visitedElems.remove(thisObj);
+ return jsString(str);
+}
+
+JSValue* arrayProtoFuncConcat(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ JSObject* arr = static_cast<JSObject*>(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList()));
+ int n = 0;
+ JSValue* curArg = thisObj;
+ JSObject* curObj = static_cast<JSObject* >(thisObj);
+ List::const_iterator it = args.begin();
+ List::const_iterator end = args.end();
+ while (1) {
+ if (curArg->isObject() && curObj->inherits(&ArrayInstance::info)) {
+ unsigned k = 0;
+ // Older versions tried to optimize out getting the length of thisObj
+ // by checking for n != 0, but that doesn't work if thisObj is an empty array.
+ unsigned length = curObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ while (k < length) {
+ if (JSValue* v = getProperty(exec, curObj, k))
+ arr->put(exec, n, v);
+ n++;
+ k++;
+ }
+ } else {
+ arr->put(exec, n, curArg);
+ n++;
+ }
+ if (it == end)
+ break;
+ curArg = *it;
+ curObj = static_cast<JSObject*>(curArg); // may be 0
+ ++it;
+ }
+ arr->put(exec, exec->propertyNames().length, jsNumber(n));
+ return arr;
+}
+
+JSValue* arrayProtoFuncPop(ExecState* exec, JSObject* thisObj, const List&)
+{
+ JSValue* result = 0;
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ if (length == 0) {
+ thisObj->put(exec, exec->propertyNames().length, jsNumber(length));
+ result = jsUndefined();
+ } else {
+ result = thisObj->get(exec, length - 1);
+ thisObj->deleteProperty(exec, length - 1);
+ thisObj->put(exec, exec->propertyNames().length, jsNumber(length - 1));
+ }
+ return result;
+}
+
+JSValue* arrayProtoFuncPush(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ for (unsigned n = 0; n < args.size(); n++)
+ thisObj->put(exec, length + n, args[n]);
+ length += args.size();
+ thisObj->put(exec, exec->propertyNames().length, jsNumber(length));
+ return jsNumber(length);
+}
+
+JSValue* arrayProtoFuncReverse(ExecState* exec, JSObject* thisObj, const List&)
+{
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ unsigned middle = length / 2;
+
+ for (unsigned k = 0; k < middle; k++) {
+ unsigned lk1 = length - k - 1;
+ JSValue* obj2 = getProperty(exec, thisObj, lk1);
+ JSValue* obj = getProperty(exec, thisObj, k);
+
+ if (obj2)
+ thisObj->put(exec, k, obj2);
+ else
+ thisObj->deleteProperty(exec, k);
+
+ if (obj)
+ thisObj->put(exec, lk1, obj);
+ else
+ thisObj->deleteProperty(exec, lk1);
+ }
+ return thisObj;
+}
+
+JSValue* arrayProtoFuncShift(ExecState* exec, JSObject* thisObj, const List&)
+{
+ JSValue* result = 0;
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ if (length == 0) {
+ thisObj->put(exec, exec->propertyNames().length, jsNumber(length));
+ result = jsUndefined();
+ } else {
+ result = thisObj->get(exec, 0);
+ for (unsigned k = 1; k < length; k++) {
+ if (JSValue* obj = getProperty(exec, thisObj, k))
+ thisObj->put(exec, k - 1, obj);
+ else
+ thisObj->deleteProperty(exec, k - 1);
+ }
+ thisObj->deleteProperty(exec, length - 1);
+ thisObj->put(exec, exec->propertyNames().length, jsNumber(length - 1));
+ }
+ return result;
+}
+
+JSValue* arrayProtoFuncSlice(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // http://developer.netscape.com/docs/manuals/js/client/jsref/array.htm#1193713 or 15.4.4.10
+
+ // We return a new array
+ JSObject* resObj = static_cast<JSObject* >(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList()));
+ JSValue* result = resObj;
+ double begin = args[0]->toInteger(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ if (begin >= 0) {
+ if (begin > length)
+ begin = length;
+ } else {
+ begin += length;
+ if (begin < 0)
+ begin = 0;
+ }
+ double end;
+ if (args[1]->isUndefined())
+ end = length;
+ else {
+ end = args[1]->toInteger(exec);
+ if (end < 0) {
+ end += length;
+ if (end < 0)
+ end = 0;
+ } else {
+ if (end > length)
+ end = length;
+ }
+ }
+
+ int n = 0;
+ int b = static_cast<int>(begin);
+ int e = static_cast<int>(end);
+ for (int k = b; k < e; k++, n++) {
+ if (JSValue* v = getProperty(exec, thisObj, k))
+ resObj->put(exec, n, v);
+ }
+ resObj->put(exec, exec->propertyNames().length, jsNumber(n));
+ return result;
+}
+
+JSValue* arrayProtoFuncSort(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ JSObject* sortFunction = 0;
+ if (!args[0]->isUndefined()) {
+ sortFunction = args[0]->toObject(exec);
+ if (!sortFunction->implementsCall())
+ sortFunction = 0;
+ }
+
+ if (thisObj->classInfo() == &ArrayInstance::info) {
+ if (sortFunction)
+ static_cast<ArrayInstance*>(thisObj)->sort(exec, sortFunction);
+ else
+ static_cast<ArrayInstance*>(thisObj)->sort(exec);
+ return thisObj;
+ }
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+
+ if (!length)
+ return thisObj;
+
+ // "Min" sort. Not the fastest, but definitely less code than heapsort
+ // or quicksort, and much less swapping than bubblesort/insertionsort.
+ for (unsigned i = 0; i < length - 1; ++i) {
+ JSValue* iObj = thisObj->get(exec, i);
+ unsigned themin = i;
+ JSValue* minObj = iObj;
+ for (unsigned j = i + 1; j < length; ++j) {
+ JSValue* jObj = thisObj->get(exec, j);
+ double compareResult;
+ if (jObj->isUndefined())
+ compareResult = 1; // don't check minObj because there's no need to differentiate == (0) from > (1)
+ else if (minObj->isUndefined())
+ compareResult = -1;
+ else if (sortFunction) {
+ List l;
+ l.append(jObj);
+ l.append(minObj);
+ compareResult = sortFunction->call(exec, exec->dynamicGlobalObject(), l)->toNumber(exec);
+ } else
+ compareResult = (jObj->toString(exec) < minObj->toString(exec)) ? -1 : 1;
+
+ if (compareResult < 0) {
+ themin = j;
+ minObj = jObj;
+ }
+ }
+ // Swap themin and i
+ if (themin > i) {
+ thisObj->put(exec, i, minObj);
+ thisObj->put(exec, themin, iObj);
+ }
+ }
+ return thisObj;
+}
+
+JSValue* arrayProtoFuncSplice(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // 15.4.4.12
+ JSObject* resObj = static_cast<JSObject* >(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList()));
+ JSValue* result = resObj;
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ if (!args.size())
+ return jsUndefined();
+ int begin = args[0]->toUInt32(exec);
+ if (begin < 0)
+ begin = std::max<int>(begin + length, 0);
+ else
+ begin = std::min<int>(begin, length);
+
+ unsigned deleteCount;
+ if (args.size() > 1)
+ deleteCount = std::min<int>(std::max<int>(args[1]->toUInt32(exec), 0), length - begin);
+ else
+ deleteCount = length - begin;
+
+ for (unsigned k = 0; k < deleteCount; k++) {
+ if (JSValue* v = getProperty(exec, thisObj, k + begin))
+ resObj->put(exec, k, v);
+ }
+ resObj->put(exec, exec->propertyNames().length, jsNumber(deleteCount));
+
+ unsigned additionalArgs = std::max<int>(args.size() - 2, 0);
+ if (additionalArgs != deleteCount) {
+ if (additionalArgs < deleteCount) {
+ for (unsigned k = begin; k < length - deleteCount; ++k) {
+ if (JSValue* v = getProperty(exec, thisObj, k + deleteCount))
+ thisObj->put(exec, k + additionalArgs, v);
+ else
+ thisObj->deleteProperty(exec, k + additionalArgs);
+ }
+ for (unsigned k = length; k > length - deleteCount + additionalArgs; --k)
+ thisObj->deleteProperty(exec, k - 1);
+ } else {
+ for (unsigned k = length - deleteCount; (int)k > begin; --k) {
+ if (JSValue* obj = getProperty(exec, thisObj, k + deleteCount - 1))
+ thisObj->put(exec, k + additionalArgs - 1, obj);
+ else
+ thisObj->deleteProperty(exec, k + additionalArgs - 1);
+ }
+ }
+ }
+ for (unsigned k = 0; k < additionalArgs; ++k)
+ thisObj->put(exec, k + begin, args[k + 2]);
+
+ thisObj->put(exec, exec->propertyNames().length, jsNumber(length - deleteCount + additionalArgs));
+ return result;
+}
+
+JSValue* arrayProtoFuncUnShift(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // 15.4.4.13
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ unsigned nrArgs = args.size();
+ if (nrArgs) {
+ for (unsigned k = length; k > 0; --k) {
+ if (JSValue* v = getProperty(exec, thisObj, k - 1))
+ thisObj->put(exec, k + nrArgs - 1, v);
+ else
+ thisObj->deleteProperty(exec, k + nrArgs - 1);
+ }
+ }
+ for (unsigned k = 0; k < nrArgs; ++k)
+ thisObj->put(exec, k, args[k]);
+ JSValue* result = jsNumber(length + nrArgs);
+ thisObj->put(exec, exec->propertyNames().length, result);
+ return result;
+}
+
+JSValue* arrayProtoFuncFilter(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ JSObject* eachFunction = args[0]->toObject(exec);
+
+ if (!eachFunction->implementsCall())
+ return throwError(exec, TypeError);
+
+ JSObject* applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicGlobalObject() : args[1]->toObject(exec);
+ JSObject* resultArray = static_cast<JSObject*>(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList()));
+
+ unsigned filterIndex = 0;
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot;
+
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+
+ JSValue* v = slot.getValue(exec, thisObj, k);
+
+ List eachArguments;
+
+ eachArguments.append(v);
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ JSValue* result = eachFunction->call(exec, applyThis, eachArguments);
+
+ if (result->toBoolean(exec))
+ resultArray->put(exec, filterIndex++, v);
+ }
+ return resultArray;
+}
+
+JSValue* arrayProtoFuncMap(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ JSObject* eachFunction = args[0]->toObject(exec);
+ if (!eachFunction->implementsCall())
+ return throwError(exec, TypeError);
+
+ JSObject* applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicGlobalObject() : args[1]->toObject(exec);
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+
+ List mapArgs;
+ mapArgs.append(jsNumber(length));
+ JSObject* resultArray = static_cast<JSObject*>(exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, mapArgs));
+
+ for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot;
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+
+ JSValue* v = slot.getValue(exec, thisObj, k);
+
+ List eachArguments;
+
+ eachArguments.append(v);
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ JSValue* result = eachFunction->call(exec, applyThis, eachArguments);
+ resultArray->put(exec, k, result);
+ }
+
+ return resultArray;
+}
+
+// Documentation for these three is available at:
+// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:every
+// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:forEach
+// http://developer-test.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Objects:Array:some
+
+JSValue* arrayProtoFuncEvery(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ JSObject* eachFunction = args[0]->toObject(exec);
+
+ if (!eachFunction->implementsCall())
+ return throwError(exec, TypeError);
+
+ JSObject* applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicGlobalObject() : args[1]->toObject(exec);
+
+ JSValue* result = jsBoolean(true);
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot;
+
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+
+ List eachArguments;
+
+ eachArguments.append(slot.getValue(exec, thisObj, k));
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ bool predicateResult = eachFunction->call(exec, applyThis, eachArguments)->toBoolean(exec);
+
+ if (!predicateResult) {
+ result = jsBoolean(false);
+ break;
+ }
+ }
+
+ return result;
+}
+
+JSValue* arrayProtoFuncForEach(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ JSObject* eachFunction = args[0]->toObject(exec);
+
+ if (!eachFunction->implementsCall())
+ return throwError(exec, TypeError);
+
+ JSObject* applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicGlobalObject() : args[1]->toObject(exec);
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot;
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+
+ List eachArguments;
+ eachArguments.append(slot.getValue(exec, thisObj, k));
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ eachFunction->call(exec, applyThis, eachArguments);
+ }
+ return jsUndefined();
+}
+
+JSValue* arrayProtoFuncSome(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ JSObject* eachFunction = args[0]->toObject(exec);
+
+ if (!eachFunction->implementsCall())
+ return throwError(exec, TypeError);
+
+ JSObject* applyThis = args[1]->isUndefinedOrNull() ? exec->dynamicGlobalObject() : args[1]->toObject(exec);
+
+ JSValue* result = jsBoolean(false);
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ for (unsigned k = 0; k < length && !exec->hadException(); ++k) {
+ PropertySlot slot;
+ if (!thisObj->getPropertySlot(exec, k, slot))
+ continue;
+
+ List eachArguments;
+ eachArguments.append(slot.getValue(exec, thisObj, k));
+ eachArguments.append(jsNumber(k));
+ eachArguments.append(thisObj);
+
+ bool predicateResult = eachFunction->call(exec, applyThis, eachArguments)->toBoolean(exec);
+
+ if (predicateResult) {
+ result = jsBoolean(true);
+ break;
+ }
+ }
+ return result;
+}
+
+JSValue* arrayProtoFuncIndexOf(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // JavaScript 1.5 Extension by Mozilla
+ // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:indexOf
+
+ unsigned index = 0;
+ double d = args[1]->toInteger(exec);
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ if (d < 0)
+ d += length;
+ if (d > 0) {
+ if (d > length)
+ index = length;
+ else
+ index = static_cast<unsigned>(d);
+ }
+
+ JSValue* searchElement = args[0];
+ for (; index < length; ++index) {
+ JSValue* e = getProperty(exec, thisObj, index);
+ if (!e)
+ continue;
+ if (strictEqual(exec, searchElement, e))
+ return jsNumber(index);
+ }
+
+ return jsNumber(-1);
+}
+
+JSValue* arrayProtoFuncLastIndexOf(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // JavaScript 1.6 Extension by Mozilla
+ // Documentation: http://developer.mozilla.org/en/docs/Core_JavaScript_1.5_Reference:Global_Objects:Array:lastIndexOf
+
+ unsigned length = thisObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ int index = length - 1;
+ double d = args[1]->toIntegerPreserveNaN(exec);
+
+ if (d < 0) {
+ d += length;
+ if (d < 0)
+ return jsNumber(-1);
+ }
+ if (d < length)
+ index = static_cast<int>(d);
+
+ JSValue* searchElement = args[0];
+ for (; index >= 0; --index) {
+ JSValue* e = getProperty(exec, thisObj, index);
+ if (!e)
+ continue;
+ if (strictEqual(exec, searchElement, e))
+ return jsNumber(index);
+ }
+
+ return jsNumber(-1);
+}
+
+// ------------------------------ ArrayObjectImp -------------------------------
+
+ArrayObjectImp::ArrayObjectImp(ExecState* exec, FunctionPrototype* funcProto, ArrayPrototype* arrayProto)
+ : InternalFunctionImp(funcProto, arrayProto->classInfo()->className)
+{
+ // ECMA 15.4.3.1 Array.prototype
+ putDirect(exec->propertyNames().prototype, arrayProto, DontEnum|DontDelete|ReadOnly);
+
+ // no. of arguments for constructor
+ putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum);
+}
+
+bool ArrayObjectImp::implementsConstruct() const
+{
+ return true;
+}
+
+// ECMA 15.4.2
+JSObject* ArrayObjectImp::construct(ExecState* exec, const List& args)
+{
+ // a single numeric argument denotes the array size (!)
+ if (args.size() == 1 && args[0]->isNumber()) {
+ uint32_t n = args[0]->toUInt32(exec);
+ if (n != args[0]->toNumber(exec))
+ return throwError(exec, RangeError, "Array size is not a small enough positive integer.");
+ return new ArrayInstance(exec->lexicalGlobalObject()->arrayPrototype(), n);
+ }
+
+ // otherwise the array is constructed with the arguments in it
+ return new ArrayInstance(exec->lexicalGlobalObject()->arrayPrototype(), args);
+}
+
+// ECMA 15.6.1
+JSValue* ArrayObjectImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
+{
+ // equivalent to 'new Array(....)'
+ return construct(exec,args);
+}
+
+}
diff --git a/JavaScriptCore/kjs/array_object.h b/JavaScriptCore/kjs/array_object.h
new file mode 100644
index 0000000..e109c47
--- /dev/null
+++ b/JavaScriptCore/kjs/array_object.h
@@ -0,0 +1,71 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef ARRAY_OBJECT_H_
+#define ARRAY_OBJECT_H_
+
+#include "array_instance.h"
+#include "function_object.h"
+#include "lookup.h"
+
+namespace KJS {
+
+ class ArrayPrototype : public ArrayInstance {
+ public:
+ ArrayPrototype(ExecState*, ObjectPrototype*);
+
+ bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+ };
+
+ class ArrayObjectImp : public InternalFunctionImp {
+ public:
+ ArrayObjectImp(ExecState*, FunctionPrototype*, ArrayPrototype*);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject* construct(ExecState*, const List&);
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+
+ };
+
+ JSValue* arrayProtoFuncToString(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncToLocaleString(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncConcat(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncJoin(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncPop(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncPush(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncReverse(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncShift(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncSlice(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncSort(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncSplice(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncUnShift(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncEvery(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncForEach(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncSome(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncIndexOf(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncFilter(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncMap(ExecState*, JSObject*, const List&);
+ JSValue* arrayProtoFuncLastIndexOf(ExecState*, JSObject*, const List&);
+
+} // namespace KJS
+
+#endif // ARRAY_OBJECT_H_
diff --git a/JavaScriptCore/kjs/bool_object.cpp b/JavaScriptCore/kjs/bool_object.cpp
new file mode 100644
index 0000000..10bb738
--- /dev/null
+++ b/JavaScriptCore/kjs/bool_object.cpp
@@ -0,0 +1,117 @@
+/*
+ * 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 "bool_object.h"
+
+#include "JSGlobalObject.h"
+#include "error_object.h"
+#include "operations.h"
+#include <wtf/Assertions.h>
+
+namespace KJS {
+
+// ------------------------------ BooleanInstance ---------------------------
+
+const ClassInfo BooleanInstance::info = { "Boolean", 0, 0 };
+
+BooleanInstance::BooleanInstance(JSObject* proto)
+ : JSWrapperObject(proto)
+{
+}
+
+// ------------------------------ BooleanPrototype --------------------------
+
+// Functions
+static JSValue* booleanProtoFuncToString(ExecState*, JSObject*, const List&);
+static JSValue* booleanProtoFuncValueOf(ExecState*, JSObject*, const List&);
+
+// ECMA 15.6.4
+
+BooleanPrototype::BooleanPrototype(ExecState* exec, ObjectPrototype* objectPrototype, FunctionPrototype* functionPrototype)
+ : BooleanInstance(objectPrototype)
+{
+ setInternalValue(jsBoolean(false));
+
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toString, booleanProtoFuncToString), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().valueOf, booleanProtoFuncValueOf), DontEnum);
+}
+
+
+// ------------------------------ Functions --------------------------
+
+// ECMA 15.6.4.2 + 15.6.4.3
+
+JSValue* booleanProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&BooleanInstance::info))
+ return throwError(exec, TypeError);
+
+ JSValue* v = static_cast<BooleanInstance*>(thisObj)->internalValue();
+ ASSERT(v);
+
+ return jsString(v->toString(exec));
+}
+JSValue* booleanProtoFuncValueOf(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&BooleanInstance::info))
+ return throwError(exec, TypeError);
+
+ JSValue* v = static_cast<BooleanInstance*>(thisObj)->internalValue();
+ ASSERT(v);
+
+ // TODO: optimize for bool case
+ return jsBoolean(v->toBoolean(exec));
+}
+
+// ------------------------------ BooleanObjectImp -----------------------------
+
+
+BooleanObjectImp::BooleanObjectImp(ExecState* exec, FunctionPrototype* functionPrototype, BooleanPrototype* booleanPrototype)
+ : InternalFunctionImp(functionPrototype, booleanPrototype->classInfo()->className)
+{
+ putDirect(exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly);
+
+ // no. of arguments for constructor
+ putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
+}
+
+
+bool BooleanObjectImp::implementsConstruct() const
+{
+ return true;
+}
+
+// ECMA 15.6.2
+JSObject* BooleanObjectImp::construct(ExecState* exec, const List& args)
+{
+ BooleanInstance* obj(new BooleanInstance(exec->lexicalGlobalObject()->booleanPrototype()));
+ obj->setInternalValue(jsBoolean(args[0]->toBoolean(exec)));
+ return obj;
+}
+
+// ECMA 15.6.1
+JSValue* BooleanObjectImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
+{
+ // TODO: optimize for bool case
+ return jsBoolean(args[0]->toBoolean(exec));
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/bool_object.h b/JavaScriptCore/kjs/bool_object.h
new file mode 100644
index 0000000..c3d5a9f
--- /dev/null
+++ b/JavaScriptCore/kjs/bool_object.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef BOOL_OBJECT_H_
+#define BOOL_OBJECT_H_
+
+#include "function_object.h"
+#include "JSWrapperObject.h"
+
+namespace KJS {
+
+ class BooleanInstance : public JSWrapperObject {
+ public:
+ BooleanInstance(JSObject* proto);
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+ };
+
+ /**
+ * @internal
+ *
+ * The initial value of Boolean.prototype (and thus all objects created
+ * with the Boolean constructor
+ */
+ class BooleanPrototype : public BooleanInstance {
+ public:
+ BooleanPrototype(ExecState*, ObjectPrototype*, FunctionPrototype*);
+ };
+
+ /**
+ * @internal
+ *
+ * The initial value of the the global variable's "Boolean" property
+ */
+ class BooleanObjectImp : public InternalFunctionImp {
+ public:
+ BooleanObjectImp(ExecState*, FunctionPrototype*, BooleanPrototype*);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject* construct(ExecState*, const List&);
+
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+ };
+
+} // namespace KJS
+
+#endif // BOOL_OBJECT_H_
diff --git a/JavaScriptCore/kjs/collector.cpp b/JavaScriptCore/kjs/collector.cpp
new file mode 100644
index 0000000..23b93df
--- /dev/null
+++ b/JavaScriptCore/kjs/collector.cpp
@@ -0,0 +1,1054 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+#include "collector.h"
+
+#include "ExecState.h"
+#include "JSGlobalObject.h"
+#include "internal.h"
+#include "list.h"
+#include "value.h"
+#include <algorithm>
+#include <setjmp.h>
+#include <stdlib.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/HashCountedSet.h>
+#include <wtf/UnusedParam.h>
+
+#if USE(MULTIPLE_THREADS)
+#include <pthread.h>
+#endif
+
+#if PLATFORM(DARWIN)
+
+#include <mach/mach_port.h>
+#include <mach/mach_init.h>
+#include <mach/task.h>
+#include <mach/thread_act.h>
+#include <mach/vm_map.h>
+
+#include "CollectorHeapIntrospector.h"
+
+#elif PLATFORM(WIN_OS)
+
+#include <windows.h>
+
+#elif PLATFORM(UNIX)
+
+#include <stdlib.h>
+#include <sys/mman.h>
+#include <unistd.h>
+
+#if PLATFORM(SOLARIS)
+#include <thread.h>
+#endif
+
+#if HAVE(PTHREAD_NP_H)
+#include <pthread_np.h>
+#else
+#include <pthread.h>
+#endif
+
+#endif
+
+#define DEBUG_COLLECTOR 0
+
+using std::max;
+
+namespace KJS {
+
+// tunable parameters
+
+const size_t SPARE_EMPTY_BLOCKS = 2;
+const size_t MIN_ARRAY_SIZE = 14;
+const size_t GROWTH_FACTOR = 2;
+const size_t LOW_WATER_FACTOR = 4;
+const size_t ALLOCATIONS_PER_COLLECTION = 4000;
+
+static CollectorHeap primaryHeap = { 0, 0, 0, 0, 0, 0, 0, NoOperation };
+static CollectorHeap numberHeap = { 0, 0, 0, 0, 0, 0, 0, NoOperation };
+
+// FIXME: I don't think this needs to be a static data member of the Collector class.
+// Just a private global like "heap" above would be fine.
+size_t Collector::mainThreadOnlyObjectCount = 0;
+
+static CollectorBlock* allocateBlock()
+{
+#if PLATFORM(DARWIN)
+ vm_address_t address = 0;
+ vm_map(current_task(), &address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE, MEMORY_OBJECT_NULL, 0, FALSE, VM_PROT_DEFAULT, VM_PROT_DEFAULT, VM_INHERIT_DEFAULT);
+#elif PLATFORM(WIN_OS)
+ // windows virtual address granularity is naturally 64k
+ LPVOID address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
+#elif HAVE(POSIX_MEMALIGN)
+ void* address;
+ posix_memalign(&address, BLOCK_SIZE, BLOCK_SIZE);
+ memset(address, 0, BLOCK_SIZE);
+#else
+ static size_t pagesize = getpagesize();
+
+ size_t extra = 0;
+ if (BLOCK_SIZE > pagesize)
+ extra = BLOCK_SIZE - pagesize;
+
+ void* mmapResult = mmap(NULL, BLOCK_SIZE + extra, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
+ uintptr_t address = reinterpret_cast<uintptr_t>(mmapResult);
+
+ size_t adjust = 0;
+ if ((address & BLOCK_OFFSET_MASK) != 0)
+ adjust = BLOCK_SIZE - (address & BLOCK_OFFSET_MASK);
+
+ if (adjust > 0)
+ munmap(reinterpret_cast<void*>(address), adjust);
+
+ if (adjust < extra)
+ munmap(reinterpret_cast<void*>(address + adjust + BLOCK_SIZE), extra - adjust);
+
+ address += adjust;
+ memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
+#endif
+
+ return reinterpret_cast<CollectorBlock*>(address);
+}
+
+static void freeBlock(CollectorBlock* block)
+{
+#if PLATFORM(DARWIN)
+ vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE);
+#elif PLATFORM(WIN_OS)
+ VirtualFree(block, BLOCK_SIZE, MEM_RELEASE);
+#elif HAVE(POSIX_MEMALIGN)
+ free(block);
+#else
+ munmap(block, BLOCK_SIZE);
+#endif
+}
+
+void Collector::recordExtraCost(size_t cost)
+{
+ // Our frequency of garbage collection tries to balance memory use against speed
+ // by collecting based on the number of newly created values. However, for values
+ // that hold on to a great deal of memory that's not in the form of other JS values,
+ // that is not good enough - in some cases a lot of those objects can pile up and
+ // use crazy amounts of memory without a GC happening. So we track these extra
+ // memory costs. Only unusually large objects are noted, and we only keep track
+ // of this extra cost until the next GC. In garbage collected languages, most values
+ // are either very short lived temporaries, or have extremely long lifetimes. So
+ // if a large value survives one garbage collection, there is not much point to
+ // collecting more frequently as long as it stays alive.
+ // NOTE: we target the primaryHeap unconditionally as JSNumber doesn't modify cost
+
+ primaryHeap.extraCost += cost;
+}
+
+template <Collector::HeapType heapType> struct HeapConstants;
+
+template <> struct HeapConstants<Collector::PrimaryHeap> {
+ static const size_t cellSize = CELL_SIZE;
+ static const size_t cellsPerBlock = CELLS_PER_BLOCK;
+ static const size_t bitmapShift = 0;
+ typedef CollectorCell Cell;
+ typedef CollectorBlock Block;
+};
+
+template <> struct HeapConstants<Collector::NumberHeap> {
+ static const size_t cellSize = SMALL_CELL_SIZE;
+ static const size_t cellsPerBlock = SMALL_CELLS_PER_BLOCK;
+ static const size_t bitmapShift = 1;
+ typedef SmallCollectorCell Cell;
+ typedef SmallCellCollectorBlock Block;
+};
+
+template <Collector::HeapType heapType> void* Collector::heapAllocate(size_t s)
+{
+ typedef typename HeapConstants<heapType>::Block Block;
+ typedef typename HeapConstants<heapType>::Cell Cell;
+
+ CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ ASSERT(s <= HeapConstants<heapType>::cellSize);
+ UNUSED_PARAM(s); // s is now only used for the above assert
+
+ ASSERT(heap.operationInProgress == NoOperation);
+ ASSERT(heapType == PrimaryHeap || heap.extraCost == 0);
+ // FIXME: If another global variable access here doesn't hurt performance
+ // too much, we could abort() in NDEBUG builds, which could help ensure we
+ // don't spend any time debugging cases where we allocate inside an object's
+ // deallocation code.
+
+ size_t numLiveObjects = heap.numLiveObjects;
+ size_t usedBlocks = heap.usedBlocks;
+ size_t i = heap.firstBlockWithPossibleSpace;
+
+ // if we have a huge amount of extra cost, we'll try to collect even if we still have
+ // free cells left.
+ if (heapType == PrimaryHeap && heap.extraCost > ALLOCATIONS_PER_COLLECTION) {
+ size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
+ size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
+ const size_t newCost = numNewObjects + heap.extraCost;
+ if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect)
+ goto collect;
+ }
+
+ ASSERT(heap.operationInProgress == NoOperation);
+#ifndef NDEBUG
+ // FIXME: Consider doing this in NDEBUG builds too (see comment above).
+ heap.operationInProgress = Allocation;
+#endif
+
+scan:
+ Block* targetBlock;
+ size_t targetBlockUsedCells;
+ if (i != usedBlocks) {
+ targetBlock = (Block*)heap.blocks[i];
+ targetBlockUsedCells = targetBlock->usedCells;
+ ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock);
+ while (targetBlockUsedCells == HeapConstants<heapType>::cellsPerBlock) {
+ if (++i == usedBlocks)
+ goto collect;
+ targetBlock = (Block*)heap.blocks[i];
+ targetBlockUsedCells = targetBlock->usedCells;
+ ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock);
+ }
+ heap.firstBlockWithPossibleSpace = i;
+ } else {
+
+collect:
+ size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
+ size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
+ const size_t newCost = numNewObjects + heap.extraCost;
+
+ if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) {
+#ifndef NDEBUG
+ heap.operationInProgress = NoOperation;
+#endif
+ bool collected = collect();
+#ifndef NDEBUG
+ heap.operationInProgress = Allocation;
+#endif
+ if (collected) {
+ numLiveObjects = heap.numLiveObjects;
+ usedBlocks = heap.usedBlocks;
+ i = heap.firstBlockWithPossibleSpace;
+ goto scan;
+ }
+ }
+
+ // didn't find a block, and GC didn't reclaim anything, need to allocate a new block
+ size_t numBlocks = heap.numBlocks;
+ if (usedBlocks == numBlocks) {
+ numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR);
+ heap.numBlocks = numBlocks;
+ heap.blocks = static_cast<CollectorBlock **>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock *)));
+ }
+
+ targetBlock = (Block*)allocateBlock();
+ targetBlock->freeList = targetBlock->cells;
+ targetBlockUsedCells = 0;
+ heap.blocks[usedBlocks] = (CollectorBlock*)targetBlock;
+ heap.usedBlocks = usedBlocks + 1;
+ heap.firstBlockWithPossibleSpace = usedBlocks;
+ }
+
+ // find a free spot in the block and detach it from the free list
+ Cell *newCell = targetBlock->freeList;
+
+ // "next" field is a cell offset -- 0 means next cell, so a zeroed block is already initialized
+ targetBlock->freeList = (newCell + 1) + newCell->u.freeCell.next;
+
+ targetBlock->usedCells = static_cast<uint32_t>(targetBlockUsedCells + 1);
+ heap.numLiveObjects = numLiveObjects + 1;
+
+#ifndef NDEBUG
+ // FIXME: Consider doing this in NDEBUG builds too (see comment above).
+ heap.operationInProgress = NoOperation;
+#endif
+
+ return newCell;
+}
+
+void* Collector::allocate(size_t s)
+{
+ return heapAllocate<PrimaryHeap>(s);
+}
+
+void* Collector::allocateNumber(size_t s)
+{
+ return heapAllocate<NumberHeap>(s);
+}
+
+static inline void* currentThreadStackBase()
+{
+#if PLATFORM(DARWIN)
+ pthread_t thread = pthread_self();
+ return pthread_get_stackaddr_np(thread);
+#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(MSVC)
+ // offset 0x18 from the FS segment register gives a pointer to
+ // the thread information block for the current thread
+ NT_TIB* pTib;
+ __asm {
+ MOV EAX, FS:[18h]
+ MOV pTib, EAX
+ }
+ return (void*)pTib->StackBase;
+#elif PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC)
+ PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
+ return (void*)pTib->StackBase;
+#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(GCC)
+ // offset 0x18 from the FS segment register gives a pointer to
+ // the thread information block for the current thread
+ NT_TIB* pTib;
+ asm ( "movl %%fs:0x18, %0\n"
+ : "=r" (pTib)
+ );
+ return (void*)pTib->StackBase;
+#elif PLATFORM(SOLARIS)
+ stack_t s;
+ thr_stksegment(&s);
+ return s.ss_sp;
+#elif PLATFORM(UNIX)
+ static void* stackBase = 0;
+ static size_t stackSize = 0;
+ static pthread_t stackThread;
+ pthread_t thread = pthread_self();
+ if (stackBase == 0 || thread != stackThread) {
+ pthread_attr_t sattr;
+ pthread_attr_init(&sattr);
+#if HAVE(PTHREAD_NP_H)
+ // e.g. on FreeBSD 5.4, neundorf@kde.org
+ pthread_attr_get_np(thread, &sattr);
+#else
+ // FIXME: this function is non-portable; other POSIX systems may have different np alternatives
+ pthread_getattr_np(thread, &sattr);
+#endif
+ int rc = pthread_attr_getstack(&sattr, &stackBase, &stackSize);
+ (void)rc; // FIXME: Deal with error code somehow? Seems fatal.
+ ASSERT(stackBase);
+ pthread_attr_destroy(&sattr);
+ stackThread = thread;
+ }
+ return static_cast<char*>(stackBase) + stackSize;
+#else
+#error Need a way to get the stack base on this platform
+#endif
+}
+
+#if USE(MULTIPLE_THREADS)
+static pthread_t mainThread;
+#endif
+
+void Collector::registerAsMainThread()
+{
+#if USE(MULTIPLE_THREADS)
+ mainThread = pthread_self();
+#endif
+}
+
+static inline bool onMainThread()
+{
+#if USE(MULTIPLE_THREADS)
+#if PLATFORM(DARWIN)
+ return pthread_main_np();
+#else
+ return !!pthread_equal(pthread_self(), mainThread);
+#endif
+#else
+ return true;
+#endif
+}
+
+#if USE(MULTIPLE_THREADS)
+
+#if PLATFORM(DARWIN)
+typedef mach_port_t PlatformThread;
+#elif PLATFORM(WIN_OS)
+struct PlatformThread {
+ PlatformThread(DWORD _id, HANDLE _handle) : id(_id), handle(_handle) {}
+ DWORD id;
+ HANDLE handle;
+};
+#endif
+
+static inline PlatformThread getCurrentPlatformThread()
+{
+#if PLATFORM(DARWIN)
+ return pthread_mach_thread_np(pthread_self());
+#elif PLATFORM(WIN_OS)
+ HANDLE threadHandle = pthread_getw32threadhandle_np(pthread_self());
+ return PlatformThread(GetCurrentThreadId(), threadHandle);
+#endif
+}
+
+class Collector::Thread {
+public:
+ Thread(pthread_t pthread, const PlatformThread& platThread, void* base)
+ : posixThread(pthread), platformThread(platThread), stackBase(base) {}
+ Thread* next;
+ pthread_t posixThread;
+ PlatformThread platformThread;
+ void* stackBase;
+};
+
+pthread_key_t registeredThreadKey;
+pthread_once_t registeredThreadKeyOnce = PTHREAD_ONCE_INIT;
+Collector::Thread* registeredThreads;
+
+static void destroyRegisteredThread(void* data)
+{
+ Collector::Thread* thread = (Collector::Thread*)data;
+
+ // Can't use JSLock convenience object here because we don't want to re-register
+ // an exiting thread.
+ JSLock::lock();
+
+ if (registeredThreads == thread) {
+ registeredThreads = registeredThreads->next;
+ } else {
+ Collector::Thread *last = registeredThreads;
+ Collector::Thread *t;
+ for (t = registeredThreads->next; t != NULL; t = t->next) {
+ if (t == thread) {
+ last->next = t->next;
+ break;
+ }
+ last = t;
+ }
+ ASSERT(t); // If t is NULL, we never found ourselves in the list.
+ }
+
+ JSLock::unlock();
+
+ delete thread;
+}
+
+static void initializeRegisteredThreadKey()
+{
+ pthread_key_create(&registeredThreadKey, destroyRegisteredThread);
+}
+
+void Collector::registerThread()
+{
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ pthread_once(&registeredThreadKeyOnce, initializeRegisteredThreadKey);
+
+ if (!pthread_getspecific(registeredThreadKey)) {
+#if PLATFORM(DARWIN)
+ if (onMainThread())
+ CollectorHeapIntrospector::init(&primaryHeap, &numberHeap);
+#endif
+
+ Collector::Thread *thread = new Collector::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase());
+
+ thread->next = registeredThreads;
+ registeredThreads = thread;
+ pthread_setspecific(registeredThreadKey, thread);
+ }
+}
+
+#endif
+
+#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) & (sizeof(char *) - 1)) == 0)
+
+// cell size needs to be a power of two for this to be valid
+#define IS_HALF_CELL_ALIGNED(p) (((intptr_t)(p) & (CELL_MASK >> 1)) == 0)
+
+void Collector::markStackObjectsConservatively(void *start, void *end)
+{
+ if (start > end) {
+ void* tmp = start;
+ start = end;
+ end = tmp;
+ }
+
+ ASSERT(((char*)end - (char*)start) < 0x1000000);
+ ASSERT(IS_POINTER_ALIGNED(start));
+ ASSERT(IS_POINTER_ALIGNED(end));
+
+ char** p = (char**)start;
+ char** e = (char**)end;
+
+ size_t usedPrimaryBlocks = primaryHeap.usedBlocks;
+ size_t usedNumberBlocks = numberHeap.usedBlocks;
+ CollectorBlock **primaryBlocks = primaryHeap.blocks;
+ CollectorBlock **numberBlocks = numberHeap.blocks;
+
+ const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
+
+ while (p != e) {
+ char* x = *p++;
+ if (IS_HALF_CELL_ALIGNED(x) && x) {
+ uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x);
+ xAsBits &= CELL_ALIGN_MASK;
+ uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK;
+ CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset);
+ // Mark the the number heap, we can mark these Cells directly to avoid the virtual call cost
+ for (size_t block = 0; block < usedNumberBlocks; block++) {
+ if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
+ Collector::markCell(reinterpret_cast<JSCell*>(xAsBits));
+ goto endMarkLoop;
+ }
+ }
+
+ // Mark the primary heap
+ for (size_t block = 0; block < usedPrimaryBlocks; block++) {
+ if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
+ if (((CollectorCell*)xAsBits)->u.freeCell.zeroIfFree != 0) {
+ JSCell* imp = reinterpret_cast<JSCell*>(xAsBits);
+ if (!imp->marked())
+ imp->mark();
+ }
+ break;
+ }
+ }
+ endMarkLoop:
+ ;
+ }
+ }
+}
+
+void Collector::markCurrentThreadConservatively()
+{
+ // setjmp forces volatile registers onto the stack
+ jmp_buf registers;
+#if COMPILER(MSVC)
+#pragma warning(push)
+#pragma warning(disable: 4611)
+#endif
+ setjmp(registers);
+#if COMPILER(MSVC)
+#pragma warning(pop)
+#endif
+
+ void* dummy;
+ void* stackPointer = &dummy;
+ void* stackBase = currentThreadStackBase();
+
+ markStackObjectsConservatively(stackPointer, stackBase);
+}
+
+#if USE(MULTIPLE_THREADS)
+
+static inline void suspendThread(const PlatformThread& platformThread)
+{
+#if PLATFORM(DARWIN)
+ thread_suspend(platformThread);
+#elif PLATFORM(WIN_OS)
+ SuspendThread(platformThread.handle);
+#else
+#error Need a way to suspend threads on this platform
+#endif
+}
+
+static inline void resumeThread(const PlatformThread& platformThread)
+{
+#if PLATFORM(DARWIN)
+ thread_resume(platformThread);
+#elif PLATFORM(WIN_OS)
+ ResumeThread(platformThread.handle);
+#else
+#error Need a way to resume threads on this platform
+#endif
+}
+
+typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
+
+#if PLATFORM(DARWIN)
+
+#if PLATFORM(X86)
+typedef i386_thread_state_t PlatformThreadRegisters;
+#elif PLATFORM(X86_64)
+typedef x86_thread_state64_t PlatformThreadRegisters;
+#elif PLATFORM(PPC)
+typedef ppc_thread_state_t PlatformThreadRegisters;
+#elif PLATFORM(PPC64)
+typedef ppc_thread_state64_t PlatformThreadRegisters;
+#else
+#error Unknown Architecture
+#endif
+
+#elif PLATFORM(WIN_OS)&& PLATFORM(X86)
+typedef CONTEXT PlatformThreadRegisters;
+#else
+#error Need a thread register struct for this platform
+#endif
+
+size_t getPlatformThreadRegisters(const PlatformThread& platformThread, PlatformThreadRegisters& regs)
+{
+#if PLATFORM(DARWIN)
+
+#if PLATFORM(X86)
+ unsigned user_count = sizeof(regs)/sizeof(int);
+ thread_state_flavor_t flavor = i386_THREAD_STATE;
+#elif PLATFORM(X86_64)
+ unsigned user_count = x86_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = x86_THREAD_STATE64;
+#elif PLATFORM(PPC)
+ unsigned user_count = PPC_THREAD_STATE_COUNT;
+ thread_state_flavor_t flavor = PPC_THREAD_STATE;
+#elif PLATFORM(PPC64)
+ unsigned user_count = PPC_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = PPC_THREAD_STATE64;
+#else
+#error Unknown Architecture
+#endif
+
+ kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)&regs, &user_count);
+ if (result != KERN_SUCCESS) {
+ WTFReportFatalError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION,
+ "JavaScript garbage collection failed because thread_get_state returned an error (%d). This is probably the result of running inside Rosetta, which is not supported.", result);
+ CRASH();
+ }
+ return user_count * sizeof(usword_t);
+// end PLATFORM(DARWIN)
+
+#elif PLATFORM(WIN_OS) && PLATFORM(X86)
+ regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS;
+ GetThreadContext(platformThread.handle, &regs);
+ return sizeof(CONTEXT);
+#else
+#error Need a way to get thread registers on this platform
+#endif
+}
+
+static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
+{
+#if PLATFORM(DARWIN)
+
+#if __DARWIN_UNIX03
+
+#if PLATFORM(X86)
+ return (void*)regs.__esp;
+#elif PLATFORM(X86_64)
+ return (void*)regs.__rsp;
+#elif PLATFORM(PPC) || PLATFORM(PPC64)
+ return (void*)regs.__r1;
+#else
+#error Unknown Architecture
+#endif
+
+#else // !__DARWIN_UNIX03
+
+#if PLATFORM(X86)
+ return (void*)regs.esp;
+#elif PLATFORM(X86_64)
+ return (void*)regs.rsp;
+#elif (PLATFORM(PPC) || PLATFORM(PPC64))
+ return (void*)regs.r1;
+#else
+#error Unknown Architecture
+#endif
+
+#endif // __DARWIN_UNIX03
+
+// end PLATFORM(DARWIN)
+#elif PLATFORM(X86) && PLATFORM(WIN_OS)
+ return (void*)(uintptr_t)regs.Esp;
+#else
+#error Need a way to get the stack pointer for another thread on this platform
+#endif
+}
+
+void Collector::markOtherThreadConservatively(Thread* thread)
+{
+ suspendThread(thread->platformThread);
+
+ PlatformThreadRegisters regs;
+ size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
+
+ // mark the thread's registers
+ markStackObjectsConservatively((void*)&regs, (void*)((char*)&regs + regSize));
+
+ void* stackPointer = otherThreadStackPointer(regs);
+ markStackObjectsConservatively(stackPointer, thread->stackBase);
+
+ resumeThread(thread->platformThread);
+}
+
+#endif
+
+void Collector::markStackObjectsConservatively()
+{
+ markCurrentThreadConservatively();
+
+#if USE(MULTIPLE_THREADS)
+ for (Thread *thread = registeredThreads; thread != NULL; thread = thread->next) {
+ if (!pthread_equal(thread->posixThread, pthread_self())) {
+ markOtherThreadConservatively(thread);
+ }
+ }
+#endif
+}
+
+typedef HashCountedSet<JSCell*> ProtectCountSet;
+
+static ProtectCountSet& protectedValues()
+{
+ static ProtectCountSet staticProtectCountSet;
+ return staticProtectCountSet;
+}
+
+void Collector::protect(JSValue *k)
+{
+ ASSERT(k);
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ if (JSImmediate::isImmediate(k))
+ return;
+
+ protectedValues().add(k->asCell());
+}
+
+void Collector::unprotect(JSValue *k)
+{
+ ASSERT(k);
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ if (JSImmediate::isImmediate(k))
+ return;
+
+ protectedValues().remove(k->asCell());
+}
+
+void Collector::collectOnMainThreadOnly(JSValue* value)
+{
+ ASSERT(value);
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ if (JSImmediate::isImmediate(value))
+ return;
+
+ JSCell* cell = value->asCell();
+ cellBlock(cell)->collectOnMainThreadOnly.set(cellOffset(cell));
+ ++mainThreadOnlyObjectCount;
+}
+
+void Collector::markProtectedObjects()
+{
+ ProtectCountSet& protectedValues = KJS::protectedValues();
+ ProtectCountSet::iterator end = protectedValues.end();
+ for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it) {
+ JSCell *val = it->first;
+ if (!val->marked())
+ val->mark();
+ }
+}
+
+void Collector::markMainThreadOnlyObjects()
+{
+#if USE(MULTIPLE_THREADS)
+ ASSERT(!onMainThread());
+#endif
+
+ // Optimization for clients that never register "main thread only" objects.
+ if (!mainThreadOnlyObjectCount)
+ return;
+
+ // FIXME: We can optimize this marking algorithm by keeping an exact set of
+ // "main thread only" objects when the "main thread only" object count is
+ // small. We don't want to keep an exact set all the time, because WebCore
+ // tends to create lots of "main thread only" objects, and all that set
+ // thrashing can be expensive.
+
+ size_t count = 0;
+
+ // We don't look at the numberHeap as primitive values can never be marked as main thread only
+ for (size_t block = 0; block < primaryHeap.usedBlocks; block++) {
+ ASSERT(count < mainThreadOnlyObjectCount);
+
+ CollectorBlock* curBlock = primaryHeap.blocks[block];
+ size_t minimumCellsToProcess = curBlock->usedCells;
+ for (size_t i = 0; (i < minimumCellsToProcess) & (i < CELLS_PER_BLOCK); i++) {
+ CollectorCell* cell = curBlock->cells + i;
+ if (cell->u.freeCell.zeroIfFree == 0)
+ ++minimumCellsToProcess;
+ else {
+ if (curBlock->collectOnMainThreadOnly.get(i)) {
+ if (!curBlock->marked.get(i)) {
+ JSCell* imp = reinterpret_cast<JSCell*>(cell);
+ imp->mark();
+ }
+ if (++count == mainThreadOnlyObjectCount)
+ return;
+ }
+ }
+ }
+ }
+}
+
+template <Collector::HeapType heapType> size_t Collector::sweep(bool currentThreadIsMainThread)
+{
+ typedef typename HeapConstants<heapType>::Block Block;
+ typedef typename HeapConstants<heapType>::Cell Cell;
+
+ UNUSED_PARAM(currentThreadIsMainThread); // currentThreadIsMainThread is only used in ASSERTs
+ // SWEEP: delete everything with a zero refcount (garbage) and unmark everything else
+ CollectorHeap& heap = heapType == Collector::PrimaryHeap ? primaryHeap : numberHeap;
+
+ size_t emptyBlocks = 0;
+ size_t numLiveObjects = heap.numLiveObjects;
+
+ for (size_t block = 0; block < heap.usedBlocks; block++) {
+ Block* curBlock = (Block*)heap.blocks[block];
+
+ size_t usedCells = curBlock->usedCells;
+ Cell* freeList = curBlock->freeList;
+
+ if (usedCells == HeapConstants<heapType>::cellsPerBlock) {
+ // special case with a block where all cells are used -- testing indicates this happens often
+ for (size_t i = 0; i < HeapConstants<heapType>::cellsPerBlock; i++) {
+ if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) {
+ Cell* cell = curBlock->cells + i;
+
+ if (heapType != Collector::NumberHeap) {
+ JSCell* imp = reinterpret_cast<JSCell*>(cell);
+ // special case for allocated but uninitialized object
+ // (We don't need this check earlier because nothing prior this point
+ // assumes the object has a valid vptr.)
+ if (cell->u.freeCell.zeroIfFree == 0)
+ continue;
+
+ ASSERT(currentThreadIsMainThread || !curBlock->collectOnMainThreadOnly.get(i));
+ if (curBlock->collectOnMainThreadOnly.get(i)) {
+ curBlock->collectOnMainThreadOnly.clear(i);
+ --Collector::mainThreadOnlyObjectCount;
+ }
+ imp->~JSCell();
+ }
+
+ --usedCells;
+ --numLiveObjects;
+
+ // put cell on the free list
+ cell->u.freeCell.zeroIfFree = 0;
+ cell->u.freeCell.next = freeList - (cell + 1);
+ freeList = cell;
+ }
+ }
+ } else {
+ size_t minimumCellsToProcess = usedCells;
+ for (size_t i = 0; (i < minimumCellsToProcess) & (i < HeapConstants<heapType>::cellsPerBlock); i++) {
+ Cell *cell = curBlock->cells + i;
+ if (cell->u.freeCell.zeroIfFree == 0) {
+ ++minimumCellsToProcess;
+ } else {
+ if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) {
+ if (heapType != Collector::NumberHeap) {
+ JSCell *imp = reinterpret_cast<JSCell*>(cell);
+ ASSERT(currentThreadIsMainThread || !curBlock->collectOnMainThreadOnly.get(i));
+ if (curBlock->collectOnMainThreadOnly.get(i)) {
+ curBlock->collectOnMainThreadOnly.clear(i);
+ --Collector::mainThreadOnlyObjectCount;
+ }
+ imp->~JSCell();
+ }
+ --usedCells;
+ --numLiveObjects;
+
+ // put cell on the free list
+ cell->u.freeCell.zeroIfFree = 0;
+ cell->u.freeCell.next = freeList - (cell + 1);
+ freeList = cell;
+ }
+ }
+ }
+ }
+
+ curBlock->usedCells = static_cast<uint32_t>(usedCells);
+ curBlock->freeList = freeList;
+ curBlock->marked.clearAll();
+
+ if (usedCells == 0) {
+ emptyBlocks++;
+ if (emptyBlocks > SPARE_EMPTY_BLOCKS) {
+#if !DEBUG_COLLECTOR
+ freeBlock((CollectorBlock*)curBlock);
+#endif
+ // swap with the last block so we compact as we go
+ heap.blocks[block] = heap.blocks[heap.usedBlocks - 1];
+ heap.usedBlocks--;
+ block--; // Don't move forward a step in this case
+
+ if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) {
+ heap.numBlocks = heap.numBlocks / GROWTH_FACTOR;
+ heap.blocks = (CollectorBlock**)fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock *));
+ }
+ }
+ }
+ }
+
+ if (heap.numLiveObjects != numLiveObjects)
+ heap.firstBlockWithPossibleSpace = 0;
+
+ heap.numLiveObjects = numLiveObjects;
+ heap.numLiveObjectsAtLastCollect = numLiveObjects;
+ heap.extraCost = 0;
+ return numLiveObjects;
+}
+
+bool Collector::collect()
+{
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation));
+ if ((primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation))
+ abort();
+
+ primaryHeap.operationInProgress = Collection;
+ numberHeap.operationInProgress = Collection;
+
+ bool currentThreadIsMainThread = onMainThread();
+
+ // MARK: first mark all referenced objects recursively starting out from the set of root objects
+
+#ifndef NDEBUG
+ // Forbid malloc during the mark phase. Marking a thread suspends it, so
+ // a malloc inside mark() would risk a deadlock with a thread that had been
+ // suspended while holding the malloc lock.
+ fastMallocForbid();
+#endif
+
+ markStackObjectsConservatively();
+ markProtectedObjects();
+ ExecState::markActiveExecStates();
+ List::markProtectedLists();
+#if USE(MULTIPLE_THREADS)
+ if (!currentThreadIsMainThread)
+ markMainThreadOnlyObjects();
+#endif
+
+#ifndef NDEBUG
+ fastMallocAllow();
+#endif
+
+ size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
+ size_t numLiveObjects = sweep<PrimaryHeap>(currentThreadIsMainThread);
+ numLiveObjects += sweep<NumberHeap>(currentThreadIsMainThread);
+
+ primaryHeap.operationInProgress = NoOperation;
+ numberHeap.operationInProgress = NoOperation;
+
+ return numLiveObjects < originalLiveObjects;
+}
+
+size_t Collector::size()
+{
+ return primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
+}
+
+size_t Collector::globalObjectCount()
+{
+ size_t count = 0;
+ if (JSGlobalObject::head()) {
+ JSGlobalObject* o = JSGlobalObject::head();
+ do {
+ ++count;
+ o = o->next();
+ } while (o != JSGlobalObject::head());
+ }
+ return count;
+}
+
+size_t Collector::protectedGlobalObjectCount()
+{
+ size_t count = 0;
+ if (JSGlobalObject::head()) {
+ JSGlobalObject* o = JSGlobalObject::head();
+ do {
+ if (protectedValues().contains(o))
+ ++count;
+ o = o->next();
+ } while (o != JSGlobalObject::head());
+ }
+ return count;
+}
+
+size_t Collector::protectedObjectCount()
+{
+ return protectedValues().size();
+}
+
+static const char *typeName(JSCell *val)
+{
+ const char *name = "???";
+ switch (val->type()) {
+ case UnspecifiedType:
+ break;
+ case UndefinedType:
+ name = "undefined";
+ break;
+ case NullType:
+ name = "null";
+ break;
+ case BooleanType:
+ name = "boolean";
+ break;
+ case StringType:
+ name = "string";
+ break;
+ case NumberType:
+ name = "number";
+ break;
+ case ObjectType: {
+ const ClassInfo *info = static_cast<JSObject *>(val)->classInfo();
+ name = info ? info->className : "Object";
+ break;
+ }
+ case GetterSetterType:
+ name = "gettersetter";
+ break;
+ }
+ return name;
+}
+
+HashCountedSet<const char*>* Collector::protectedObjectTypeCounts()
+{
+ HashCountedSet<const char*>* counts = new HashCountedSet<const char*>;
+
+ ProtectCountSet& protectedValues = KJS::protectedValues();
+ ProtectCountSet::iterator end = protectedValues.end();
+ for (ProtectCountSet::iterator it = protectedValues.begin(); it != end; ++it)
+ counts->add(typeName(it->first));
+
+ return counts;
+}
+
+bool Collector::isBusy()
+{
+ return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation);
+}
+
+void Collector::reportOutOfMemoryToAllExecStates()
+{
+ ExecStateStack::const_iterator end = ExecState::activeExecStates().end();
+ for (ExecStateStack::const_iterator it = ExecState::activeExecStates().begin(); it != end; ++it) {
+ (*it)->setException(Error::create(*it, GeneralError, "Out of memory"));
+ }
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/collector.h b/JavaScriptCore/kjs/collector.h
new file mode 100644
index 0000000..436a6af
--- /dev/null
+++ b/JavaScriptCore/kjs/collector.h
@@ -0,0 +1,207 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 KJSCOLLECTOR_H_
+#define KJSCOLLECTOR_H_
+
+#include <string.h>
+#include <wtf/HashCountedSet.h>
+
+namespace KJS {
+
+ class JSCell;
+ class JSValue;
+ class CollectorBlock;
+
+ class Collector {
+ public:
+ static void* allocate(size_t s);
+ static void* allocateNumber(size_t s);
+ static bool collect();
+ static bool isBusy(); // true if an allocation or collection is in progress
+
+ static const size_t minExtraCostSize = 256;
+
+ static void reportExtraMemoryCost(size_t cost);
+
+ static size_t size();
+
+ static void protect(JSValue*);
+ static void unprotect(JSValue*);
+
+ static void collectOnMainThreadOnly(JSValue*);
+
+ static size_t globalObjectCount();
+ static size_t protectedObjectCount();
+ static size_t protectedGlobalObjectCount();
+ static HashCountedSet<const char*>* protectedObjectTypeCounts();
+
+ class Thread;
+ static void registerThread();
+
+ static void registerAsMainThread();
+
+ static bool isCellMarked(const JSCell*);
+ static void markCell(JSCell*);
+
+ enum HeapType { PrimaryHeap, NumberHeap };
+
+ private:
+ template <Collector::HeapType heapType> static void* heapAllocate(size_t s);
+ template <Collector::HeapType heapType> static size_t sweep(bool);
+ static const CollectorBlock* cellBlock(const JSCell*);
+ static CollectorBlock* cellBlock(JSCell*);
+ static size_t cellOffset(const JSCell*);
+
+ Collector();
+
+ static void recordExtraCost(size_t);
+ static void markProtectedObjects();
+ static void markMainThreadOnlyObjects();
+ static void markCurrentThreadConservatively();
+ static void markOtherThreadConservatively(Thread*);
+ static void markStackObjectsConservatively();
+ static void markStackObjectsConservatively(void* start, void* end);
+
+ static size_t mainThreadOnlyObjectCount;
+ static bool memoryFull;
+ static void reportOutOfMemoryToAllExecStates();
+ };
+
+ // tunable parameters
+ template<size_t bytesPerWord> struct CellSize;
+
+ // cell size needs to be a power of two for certain optimizations in collector.cpp
+ template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 32; }; // 32-bit
+ template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; }; // 64-bit
+ const size_t BLOCK_SIZE = 16 * 4096; // 64k
+
+ // derived constants
+ const size_t BLOCK_OFFSET_MASK = BLOCK_SIZE - 1;
+ const size_t BLOCK_MASK = ~BLOCK_OFFSET_MASK;
+ const size_t MINIMUM_CELL_SIZE = CellSize<sizeof(void*)>::m_value;
+ const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + (MINIMUM_CELL_SIZE % sizeof(double) != 0 ? sizeof(double) : 0);
+ const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double);
+ const size_t SMALL_CELL_SIZE = CELL_SIZE / 2;
+ const size_t CELL_MASK = CELL_SIZE - 1;
+ const size_t CELL_ALIGN_MASK = ~CELL_MASK;
+ const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2);
+ const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK;
+ const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8;
+ const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t);
+
+ struct CollectorBitmap {
+ uint32_t bits[BITMAP_WORDS];
+ bool get(size_t n) const { return !!(bits[n >> 5] & (1 << (n & 0x1F))); }
+ void set(size_t n) { bits[n >> 5] |= (1 << (n & 0x1F)); }
+ void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); }
+ void clearAll() { memset(bits, 0, sizeof(bits)); }
+ };
+
+ struct CollectorCell {
+ union {
+ double memory[CELL_ARRAY_LENGTH];
+ struct {
+ void* zeroIfFree;
+ ptrdiff_t next;
+ } freeCell;
+ } u;
+ };
+
+ struct SmallCollectorCell {
+ union {
+ double memory[CELL_ARRAY_LENGTH / 2];
+ struct {
+ void* zeroIfFree;
+ ptrdiff_t next;
+ } freeCell;
+ } u;
+ };
+
+ class CollectorBlock {
+ public:
+ CollectorCell cells[CELLS_PER_BLOCK];
+ uint32_t usedCells;
+ CollectorCell* freeList;
+ CollectorBitmap marked;
+ CollectorBitmap collectOnMainThreadOnly;
+ };
+
+ class SmallCellCollectorBlock {
+ public:
+ SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK];
+ uint32_t usedCells;
+ SmallCollectorCell* freeList;
+ CollectorBitmap marked;
+ CollectorBitmap collectOnMainThreadOnly;
+ };
+
+ enum OperationInProgress { NoOperation, Allocation, Collection };
+
+ struct CollectorHeap {
+ CollectorBlock** blocks;
+ size_t numBlocks;
+ size_t usedBlocks;
+ size_t firstBlockWithPossibleSpace;
+
+ size_t numLiveObjects;
+ size_t numLiveObjectsAtLastCollect;
+ size_t extraCost;
+
+ OperationInProgress operationInProgress;
+ };
+
+ inline const CollectorBlock* Collector::cellBlock(const JSCell* cell)
+ {
+ return reinterpret_cast<const CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK);
+ }
+
+ inline CollectorBlock* Collector::cellBlock(JSCell* cell)
+ {
+ return const_cast<CollectorBlock*>(cellBlock(const_cast<const JSCell*>(cell)));
+ }
+
+ inline size_t Collector::cellOffset(const JSCell* cell)
+ {
+ return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE;
+ }
+
+ inline bool Collector::isCellMarked(const JSCell* cell)
+ {
+ return cellBlock(cell)->marked.get(cellOffset(cell));
+ }
+
+ inline void Collector::markCell(JSCell* cell)
+ {
+ cellBlock(cell)->marked.set(cellOffset(cell));
+ }
+
+ inline void Collector::reportExtraMemoryCost(size_t cost)
+ {
+ if (cost > minExtraCostSize)
+ recordExtraCost(cost / (CELL_SIZE * 2));
+ }
+
+} // namespace KJS
+
+#endif /* KJSCOLLECTOR_H_ */
diff --git a/JavaScriptCore/kjs/completion.h b/JavaScriptCore/kjs/completion.h
new file mode 100644
index 0000000..09f3db7
--- /dev/null
+++ b/JavaScriptCore/kjs/completion.h
@@ -0,0 +1,60 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * 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 KJS_COMPLETION_H
+#define KJS_COMPLETION_H
+
+namespace KJS {
+
+ class JSValue;
+
+ enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted };
+
+ /**
+ * Completion objects are used to convey the return status and value
+ * from functions.
+ *
+ * See FunctionImp::execute()
+ *
+ * @see FunctionImp
+ *
+ * @short Handle for a Completion type.
+ */
+ class Completion {
+ public:
+ Completion(ComplType type = Normal, JSValue* value = 0)
+ : m_type(type), m_value(value) { }
+
+ ComplType complType() const { return m_type; }
+ JSValue* value() const { return m_value; }
+ void setValue(JSValue* v) { m_value = v; }
+ bool isValueCompletion() const { return !!m_value; }
+
+ private:
+ ComplType m_type;
+ JSValue* m_value;
+ };
+
+}
+
+#endif
diff --git a/JavaScriptCore/kjs/config.h b/JavaScriptCore/kjs/config.h
new file mode 100644
index 0000000..22ae717
--- /dev/null
+++ b/JavaScriptCore/kjs/config.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Samuel Weinig <sam.weinig@gmail.com>
+ *
+ * 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 <wtf/Platform.h>
+
+#if PLATFORM(MAC)
+#define HAVE_JNI 1
+#endif
+
+#if PLATFORM(DARWIN)
+
+#define HAVE_ERRNO_H 1
+#define HAVE_MMAP 1
+#define HAVE_MERGESORT 1
+#define HAVE_SBRK 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_TIME_H 1
+#define HAVE_SYS_TIMEB_H 1
+
+#elif PLATFORM(WIN_OS)
+
+// If we don't define these, they get defined in windef.h.
+// We want to use std::min and std::max
+#define max max
+#define min min
+
+#if !COMPILER(MSVC7)
+// We need to define this before the first #include of stdlib.h or it won't contain rand_s.
+#ifndef _CRT_RAND_S
+#define _CRT_RAND_S
+#endif
+#endif
+
+#define HAVE_FLOAT_H 1
+#define HAVE_SYS_TIMEB_H 1
+#define HAVE_VIRTUALALLOC 1
+
+#else
+
+/* FIXME: is this actually used or do other platforms generate their own config.h? */
+
+#define HAVE_ERRNO_H 1
+#define HAVE_MMAP 1
+#define HAVE_SBRK 1
+#define HAVE_STRINGS_H 1
+#define HAVE_SYS_PARAM_H 1
+#define HAVE_SYS_TIME_H 1
+
+#endif
+
+#if PLATFORM(FREEBSD)
+#define HAVE_PTHREAD_NP_H 1
+#endif
+
+/* FIXME: if all platforms have these, do they really need #defines? */
+#define HAVE_STDINT_H 1
+#define HAVE_STRING_H 1
+
+#define WTF_CHANGES 1
+
+#ifdef __cplusplus
+#undef new
+#undef delete
+#include <wtf/FastMalloc.h>
+#endif
+
+// this breaks compilation of <QFontDatabase>, at least, so turn it off for now
+// Also generates errors on wx on Windows, because these functions
+// are used from wx headers.
+#if !PLATFORM(QT) && !PLATFORM(WX)
+#include <wtf/DisallowCType.h>
+#endif
diff --git a/JavaScriptCore/kjs/create_hash_table b/JavaScriptCore/kjs/create_hash_table
new file mode 100755
index 0000000..6800722
--- /dev/null
+++ b/JavaScriptCore/kjs/create_hash_table
@@ -0,0 +1,250 @@
+#! /usr/bin/perl -w
+#
+# Static Hashtable Generator
+#
+# (c) 2000-2002 by Harri Porten <porten@kde.org> and
+# David Faure <faure@kde.org>
+# Modified (c) 2004 by Nikolas Zimmermann <wildfox@kde.org>
+# Copyright (C) 2007 Apple Inc. All rights reserved.
+#
+# Part of the KJS library.
+#
+# 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
+#
+
+use strict;
+
+my $file = $ARGV[0];
+shift;
+my $includelookup = 0;
+
+# Use -i as second argument to make it include "lookup.h"
+$includelookup = 1 if (defined($ARGV[0]) && $ARGV[0] eq "-i");
+
+# Use -n as second argument to make it use the third argument as namespace parameter ie. -n KDOM
+my $useNameSpace = $ARGV[1] if (defined($ARGV[0]) && $ARGV[0] eq "-n");
+
+print STDERR "Creating hashtable for $file\n";
+open(IN, $file) or die "No such file $file";
+
+my @keys = ();
+my @values = ();
+my @attrs = ();
+my @params = ();
+my @hashes = ();
+my @table = ();
+my @links = ();
+
+my $inside = 0;
+my $name;
+my $size;
+my $hashSizeMask;
+my $banner = 0;
+sub calcTable();
+sub output();
+sub hashValue($);
+
+while (<IN>) {
+ chop;
+ s/^\s*//g;
+ if (/^\#|^$/) {
+ # comment. do nothing
+ } elsif (/^\@begin/ && !$inside) {
+ if (/^\@begin\s*([:_\w]+)\s*\d*\s*$/) {
+ $inside = 1;
+ $name = $1;
+ } else {
+ printf STDERR "WARNING: \@begin without table name and hashsize, skipping $_\n";
+ }
+ } elsif (/^\@end\s*$/ && $inside) {
+
+ calcTable();
+
+ output();
+ @keys = ();
+ @values = ();
+ @attrs = ();
+ @params = ();
+ @table = ();
+ @links = ();
+ @hashes = ();
+ $inside = 0;
+ } elsif (/^(\S+)\s*(\S+)\s*([\w\|]*)\s*(\w*)\s*$/ && $inside) {
+ my $key = $1;
+ my $val = $2;
+ my $att = $3;
+ my $param = $4;
+ push(@keys, $key);
+ push(@values, $val);
+ push(@hashes, hashValue($key));
+ printf STDERR "WARNING: Number of arguments missing for $key/$val\n"
+ if ( $att =~ m/Function/ && length($param) == 0);
+ push(@attrs, length($att) > 0 ? $att : "0");
+ push(@params, length($param) > 0 ? $param : "0");
+ } elsif ($inside) {
+ die "invalid data {" . $_ . "}";
+ }
+}
+
+die "missing closing \@end" if ($inside);
+
+sub ceilingToPowerOf2
+{
+ my ($size) = @_;
+
+ my $powerOf2 = 1;
+ while ($size > $powerOf2) {
+ $powerOf2 <<= 1;
+ }
+
+ return $powerOf2;
+}
+
+sub calcTable() {
+ my $hashsize = ceilingToPowerOf2(2 * @keys);
+ $hashSizeMask = $hashsize - 1;
+ $size = $hashsize;
+ my $collisions = 0;
+ my $maxdepth = 0;
+ my $i = 0;
+ foreach my $key (@keys) {
+ my $depth = 0;
+ my $h = hashValue($key) % $hashsize;
+ while (defined($table[$h])) {
+ if (defined($links[$h])) {
+ $h = $links[$h];
+ $depth++;
+ } else {
+ $collisions++;
+ $links[$h] = $size;
+ $h = $size;
+ $size++;
+ }
+ }
+ $table[$h] = $i;
+ $i++;
+ $maxdepth = $depth if ( $depth > $maxdepth);
+ }
+
+ # Ensure table is big enough (in case of undef entries at the end)
+ if ( $#table+1 < $size ) {
+ $#table = $size-1;
+ }
+}
+
+sub leftShift($$) {
+ my ($value, $distance) = @_;
+ return (($value << $distance) & 0xFFFFFFFF);
+}
+
+# Paul Hsieh's SuperFastHash
+# http://www.azillionmonkeys.com/qed/hash.html
+# Ported from UString..
+sub hashValue($) {
+ my @chars = split(/ */, $_[0]);
+
+ # This hash is designed to work on 16-bit chunks at a time. But since the normal case
+ # (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
+ # were 16-bit chunks, which should give matching results
+
+ my $EXP2_32 = 4294967296;
+
+ my $hash = 0x9e3779b9;
+ my $l = scalar @chars; #I wish this was in Ruby --- Maks
+ my $rem = $l & 1;
+ $l = $l >> 1;
+
+ my $s = 0;
+
+ # Main loop
+ for (; $l > 0; $l--) {
+ $hash += ord($chars[$s]);
+ my $tmp = leftShift(ord($chars[$s+1]), 11) ^ $hash;
+ $hash = (leftShift($hash, 16)% $EXP2_32) ^ $tmp;
+ $s += 2;
+ $hash += $hash >> 11;
+ $hash %= $EXP2_32;
+ }
+
+ # Handle end case
+ if ($rem !=0) {
+ $hash += ord($chars[$s]);
+ $hash ^= (leftShift($hash, 11)% $EXP2_32);
+ $hash += $hash >> 17;
+ }
+
+ # Force "avalanching" of final 127 bits
+ $hash ^= leftShift($hash, 3);
+ $hash += ($hash >> 5);
+ $hash = ($hash% $EXP2_32);
+ $hash ^= (leftShift($hash, 2)% $EXP2_32);
+ $hash += ($hash >> 15);
+ $hash = $hash% $EXP2_32;
+ $hash ^= (leftShift($hash, 10)% $EXP2_32);
+
+ # this avoids ever returning a hash code of 0, since that is used to
+ # signal "hash not computed yet", using a value that is likely to be
+ # effectively the same as 0 when the low bits are masked
+ $hash = 0x80000000 if ($hash == 0);
+
+ return $hash;
+}
+
+sub output() {
+ if (!$banner) {
+ $banner = 1;
+ print "/* Automatically generated from $file using $0. DO NOT EDIT ! */\n";
+ }
+
+ my $nameEntries = "${name}Entries";
+ $nameEntries =~ s/:/_/g;
+
+ print "\n#include \"lookup.h\"\n" if ($includelookup);
+ if ($useNameSpace) {
+ print "\nnamespace ${useNameSpace}\n{\n";
+ print "\nusing namespace KJS;";
+ } else {
+ print "\nnamespace KJS {\n";
+ }
+ print "\nstatic const struct HashEntry ".$nameEntries."[] = {\n";
+ my $i = 0;
+
+ foreach my $entry (@table) {
+ if (defined($entry)) {
+ my $key = $keys[$entry];
+ print " \{ \"" . $key . "\"";
+ print ", { (intptr_t)" . $values[$entry] . " }";
+ print ", " . $attrs[$entry];
+ print ", " . $params[$entry];
+ print ", ";
+ if (defined($links[$i])) {
+ print "&" . $nameEntries . "[" . $links[$i] . "]" . " \}";
+ } else {
+ print "0 \}"
+ }
+ print "/* " . $hashes[$entry] . " */ ";
+ } else {
+ print " { 0, { 0 }, 0, 0, 0 }";
+ }
+ print "," unless ($i == $size - 1);
+ print "\n";
+ $i++;
+ }
+
+ print "};\n\n";
+ print "const struct HashTable $name = ";
+ print "\{ 3, $size, $nameEntries, $hashSizeMask \};\n\n";
+ print "} // namespace\n";
+}
diff --git a/JavaScriptCore/kjs/date_object.cpp b/JavaScriptCore/kjs/date_object.cpp
new file mode 100644
index 0000000..96e4d2b
--- /dev/null
+++ b/JavaScriptCore/kjs/date_object.cpp
@@ -0,0 +1,1669 @@
+/*
+ * 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 "date_object.h"
+#include "date_object.lut.h"
+#include "internal.h"
+
+#if HAVE(ERRNO_H)
+#include <errno.h>
+#endif
+
+#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
+
+#include <float.h>
+#include <limits.h>
+#include <locale.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+
+#include "error_object.h"
+#include "operations.h"
+#include "DateMath.h"
+
+#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/StringExtras.h>
+#include <wtf/UnusedParam.h>
+
+#if PLATFORM(MAC)
+ #include <CoreFoundation/CoreFoundation.h>
+#endif
+
+using namespace WTF;
+
+namespace KJS {
+
+static double parseDate(const UString&);
+static double timeClip(double);
+
+inline int gmtoffset(const GregorianDateTime& t)
+{
+ return t.utcOffset;
+}
+
+
+/**
+ * @internal
+ *
+ * Class to implement all methods that are properties of the
+ * Date object
+ */
+class DateObjectFuncImp : public InternalFunctionImp {
+public:
+ DateObjectFuncImp(ExecState *, FunctionPrototype *, int i, int len, const Identifier& );
+
+ virtual JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args);
+
+ enum { Parse, UTC };
+
+private:
+ int id;
+};
+
+#if PLATFORM(MAC)
+
+static CFDateFormatterStyle styleFromArgString(const UString& string, CFDateFormatterStyle defaultStyle)
+{
+ if (string == "short")
+ return kCFDateFormatterShortStyle;
+ if (string == "medium")
+ return kCFDateFormatterMediumStyle;
+ if (string == "long")
+ return kCFDateFormatterLongStyle;
+ if (string == "full")
+ return kCFDateFormatterFullStyle;
+ return defaultStyle;
+}
+
+static UString formatLocaleDate(ExecState *exec, double time, bool includeDate, bool includeTime, const List &args)
+{
+ CFDateFormatterStyle dateStyle = (includeDate ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
+ CFDateFormatterStyle timeStyle = (includeTime ? kCFDateFormatterLongStyle : kCFDateFormatterNoStyle);
+
+ bool useCustomFormat = false;
+ UString customFormatString;
+
+ UString arg0String = args[0]->toString(exec);
+ if (arg0String == "custom" && !args[1]->isUndefined()) {
+ useCustomFormat = true;
+ customFormatString = args[1]->toString(exec);
+ } else if (includeDate && includeTime && !args[1]->isUndefined()) {
+ dateStyle = styleFromArgString(arg0String, dateStyle);
+ timeStyle = styleFromArgString(args[1]->toString(exec), timeStyle);
+ } else if (includeDate && !args[0]->isUndefined()) {
+ dateStyle = styleFromArgString(arg0String, dateStyle);
+ } else if (includeTime && !args[0]->isUndefined()) {
+ timeStyle = styleFromArgString(arg0String, timeStyle);
+ }
+
+ CFLocaleRef locale = CFLocaleCopyCurrent();
+ CFDateFormatterRef formatter = CFDateFormatterCreate(0, locale, dateStyle, timeStyle);
+ CFRelease(locale);
+
+ if (useCustomFormat) {
+ CFStringRef customFormatCFString = CFStringCreateWithCharacters(0, (UniChar *)customFormatString.data(), customFormatString.size());
+ CFDateFormatterSetFormat(formatter, customFormatCFString);
+ CFRelease(customFormatCFString);
+ }
+
+ CFStringRef string = CFDateFormatterCreateStringWithAbsoluteTime(0, formatter, time - kCFAbsoluteTimeIntervalSince1970);
+
+ CFRelease(formatter);
+
+ // We truncate the string returned from CFDateFormatter if it's absurdly long (> 200 characters).
+ // That's not great error handling, but it just won't happen so it doesn't matter.
+ UChar buffer[200];
+ const size_t bufferLength = sizeof(buffer) / sizeof(buffer[0]);
+ size_t length = CFStringGetLength(string);
+ ASSERT(length <= bufferLength);
+ if (length > bufferLength)
+ length = bufferLength;
+ CFStringGetCharacters(string, CFRangeMake(0, length), reinterpret_cast<UniChar *>(buffer));
+
+ CFRelease(string);
+
+ return UString(buffer, length);
+}
+
+#else
+
+enum LocaleDateTimeFormat { LocaleDateAndTime, LocaleDate, LocaleTime };
+
+static JSCell* formatLocaleDate(const GregorianDateTime& gdt, const LocaleDateTimeFormat format)
+{
+ static const char* formatStrings[] = {"%#c", "%#x", "%X"};
+
+ // Offset year if needed
+ struct tm localTM = gdt;
+ int year = gdt.year + 1900;
+ bool yearNeedsOffset = year < 1900 || year > 2038;
+ if (yearNeedsOffset) {
+ localTM.tm_year = equivalentYearForDST(year) - 1900;
+ }
+
+ // Do the formatting
+ const int bufsize=128;
+ char timebuffer[bufsize];
+ size_t ret = strftime(timebuffer, bufsize, formatStrings[format], &localTM);
+
+ if ( ret == 0 )
+ return jsString("");
+
+ // Copy original into the buffer
+ if (yearNeedsOffset && format != LocaleTime) {
+ static const int yearLen = 5; // FIXME will be a problem in the year 10,000
+ char yearString[yearLen];
+
+ snprintf(yearString, yearLen, "%d", localTM.tm_year + 1900);
+ char* yearLocation = strstr(timebuffer, yearString);
+ snprintf(yearString, yearLen, "%d", year);
+
+ strncpy(yearLocation, yearString, yearLen - 1);
+ }
+
+ return jsString(timebuffer);
+}
+
+#endif // PLATFORM(WIN_OS)
+
+static UString formatDate(const GregorianDateTime &t)
+{
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "%s %s %02d %04d",
+ weekdayName[(t.weekDay + 6) % 7],
+ monthName[t.month], t.monthDay, t.year + 1900);
+ return buffer;
+}
+
+static UString formatDateUTCVariant(const GregorianDateTime &t)
+{
+ char buffer[100];
+ snprintf(buffer, sizeof(buffer), "%s, %02d %s %04d",
+ weekdayName[(t.weekDay + 6) % 7],
+ t.monthDay, monthName[t.month], t.year + 1900);
+ return buffer;
+}
+
+static UString formatTime(const GregorianDateTime &t, bool utc)
+{
+ char buffer[100];
+ if (utc) {
+ snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second);
+ } else {
+ int offset = abs(gmtoffset(t));
+ char tzname[70];
+ struct tm gtm = t;
+ strftime(tzname, sizeof(tzname), "%Z", &gtm);
+
+ if (tzname[0]) {
+ snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)",
+ t.hour, t.minute, t.second,
+ gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, tzname);
+ } else {
+ snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d",
+ t.hour, t.minute, t.second,
+ gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60);
+ }
+ }
+ return UString(buffer);
+}
+
+// Converts a list of arguments sent to a Date member function into milliseconds, updating
+// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
+//
+// Format of member function: f([hour,] [min,] [sec,] [ms])
+static bool fillStructuresUsingTimeArgs(ExecState* exec, const List& args, int maxArgs, double* ms, GregorianDateTime* t)
+{
+ double milliseconds = 0;
+ bool ok = true;
+ int idx = 0;
+ int numArgs = args.size();
+
+ // JS allows extra trailing arguments -- ignore them
+ if (numArgs > maxArgs)
+ numArgs = maxArgs;
+
+ // hours
+ if (maxArgs >= 4 && idx < numArgs) {
+ t->hour = 0;
+ milliseconds += args[idx++]->toInt32(exec, ok) * msPerHour;
+ }
+
+ // minutes
+ if (maxArgs >= 3 && idx < numArgs && ok) {
+ t->minute = 0;
+ milliseconds += args[idx++]->toInt32(exec, ok) * msPerMinute;
+ }
+
+ // seconds
+ if (maxArgs >= 2 && idx < numArgs && ok) {
+ t->second = 0;
+ milliseconds += args[idx++]->toInt32(exec, ok) * msPerSecond;
+ }
+
+ if (!ok)
+ return false;
+
+ // milliseconds
+ if (idx < numArgs) {
+ double millis = args[idx]->toNumber(exec);
+ ok = isfinite(millis);
+ milliseconds += millis;
+ } else
+ milliseconds += *ms;
+
+ *ms = milliseconds;
+ return ok;
+}
+
+// Converts a list of arguments sent to a Date member function into years, months, and milliseconds, updating
+// ms (representing milliseconds) and t (representing the rest of the date structure) appropriately.
+//
+// Format of member function: f([years,] [months,] [days])
+static bool fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, GregorianDateTime *t)
+{
+ int idx = 0;
+ bool ok = true;
+ int numArgs = args.size();
+
+ // JS allows extra trailing arguments -- ignore them
+ if (numArgs > maxArgs)
+ numArgs = maxArgs;
+
+ // years
+ if (maxArgs >= 3 && idx < numArgs)
+ t->year = args[idx++]->toInt32(exec, ok) - 1900;
+
+ // months
+ if (maxArgs >= 2 && idx < numArgs && ok)
+ t->month = args[idx++]->toInt32(exec, ok);
+
+ // days
+ if (idx < numArgs && ok) {
+ t->monthDay = 0;
+ *ms += args[idx]->toInt32(exec, ok) * msPerDay;
+ }
+
+ return ok;
+}
+
+// ------------------------------ DateInstance ------------------------------
+
+const ClassInfo DateInstance::info = {"Date", 0, 0};
+
+DateInstance::DateInstance(JSObject *proto)
+ : JSWrapperObject(proto)
+{
+}
+
+bool DateInstance::getTime(GregorianDateTime &t, int &offset) const
+{
+ double milli = internalValue()->getNumber();
+ if (isnan(milli))
+ return false;
+
+ msToGregorianDateTime(milli, false, t);
+ offset = gmtoffset(t);
+ return true;
+}
+
+bool DateInstance::getUTCTime(GregorianDateTime &t) const
+{
+ double milli = internalValue()->getNumber();
+ if (isnan(milli))
+ return false;
+
+ msToGregorianDateTime(milli, true, t);
+ return true;
+}
+
+bool DateInstance::getTime(double &milli, int &offset) const
+{
+ milli = internalValue()->getNumber();
+ if (isnan(milli))
+ return false;
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, false, t);
+ offset = gmtoffset(t);
+ return true;
+}
+
+bool DateInstance::getUTCTime(double &milli) const
+{
+ milli = internalValue()->getNumber();
+ if (isnan(milli))
+ return false;
+
+ return true;
+}
+
+static inline bool isTime_tSigned()
+{
+ time_t minusOne = (time_t)(-1);
+ return minusOne < 0;
+}
+
+// ------------------------------ DatePrototype -----------------------------
+
+const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, &dateTable};
+
+/* Source for date_object.lut.h
+ FIXMEL We could use templates to simplify the UTC variants.
+@begin dateTable 61
+ toString dateProtoFuncToString DontEnum|Function 0
+ toUTCString dateProtoFuncToUTCString DontEnum|Function 0
+ toDateString dateProtoFuncToDateString DontEnum|Function 0
+ toTimeString dateProtoFuncToTimeString DontEnum|Function 0
+ toLocaleString dateProtoFuncToLocaleString DontEnum|Function 0
+ toLocaleDateString dateProtoFuncToLocaleDateString DontEnum|Function 0
+ toLocaleTimeString dateProtoFuncToLocaleTimeString DontEnum|Function 0
+ valueOf dateProtoFuncValueOf DontEnum|Function 0
+ getTime dateProtoFuncGetTime DontEnum|Function 0
+ getFullYear dateProtoFuncGetFullYear DontEnum|Function 0
+ getUTCFullYear dateProtoFuncGetUTCFullYear DontEnum|Function 0
+ toGMTString dateProtoFuncToGMTString DontEnum|Function 0
+ getMonth dateProtoFuncGetMonth DontEnum|Function 0
+ getUTCMonth dateProtoFuncGetUTCMonth DontEnum|Function 0
+ getDate dateProtoFuncGetDate DontEnum|Function 0
+ getUTCDate dateProtoFuncGetUTCDate DontEnum|Function 0
+ getDay dateProtoFuncGetDay DontEnum|Function 0
+ getUTCDay dateProtoFuncGetUTCDay DontEnum|Function 0
+ getHours dateProtoFuncGetHours DontEnum|Function 0
+ getUTCHours dateProtoFuncGetUTCHours DontEnum|Function 0
+ getMinutes dateProtoFuncGetMinutes DontEnum|Function 0
+ getUTCMinutes dateProtoFuncGetUTCMinutes DontEnum|Function 0
+ getSeconds dateProtoFuncGetSeconds DontEnum|Function 0
+ getUTCSeconds dateProtoFuncGetUTCSeconds DontEnum|Function 0
+ getMilliseconds dateProtoFuncGetMilliSeconds DontEnum|Function 0
+ getUTCMilliseconds dateProtoFuncGetUTCMilliseconds DontEnum|Function 0
+ getTimezoneOffset dateProtoFuncGetTimezoneOffset DontEnum|Function 0
+ setTime dateProtoFuncSetTime DontEnum|Function 1
+ setMilliseconds dateProtoFuncSetMilliSeconds DontEnum|Function 1
+ setUTCMilliseconds dateProtoFuncSetUTCMilliseconds DontEnum|Function 1
+ setSeconds dateProtoFuncSetSeconds DontEnum|Function 2
+ setUTCSeconds dateProtoFuncSetUTCSeconds DontEnum|Function 2
+ setMinutes dateProtoFuncSetMinutes DontEnum|Function 3
+ setUTCMinutes dateProtoFuncSetUTCMinutes DontEnum|Function 3
+ setHours dateProtoFuncSetHours DontEnum|Function 4
+ setUTCHours dateProtoFuncSetUTCHours DontEnum|Function 4
+ setDate dateProtoFuncSetDate DontEnum|Function 1
+ setUTCDate dateProtoFuncSetUTCDate DontEnum|Function 1
+ setMonth dateProtoFuncSetMonth DontEnum|Function 2
+ setUTCMonth dateProtoFuncSetUTCMonth DontEnum|Function 2
+ setFullYear dateProtoFuncSetFullYear DontEnum|Function 3
+ setUTCFullYear dateProtoFuncSetUTCFullYear DontEnum|Function 3
+ setYear dateProtoFuncSetYear DontEnum|Function 1
+ getYear dateProtoFuncGetYear DontEnum|Function 0
+@end
+*/
+// ECMA 15.9.4
+
+DatePrototype::DatePrototype(ExecState *, ObjectPrototype *objectProto)
+ : DateInstance(objectProto)
+{
+ setInternalValue(jsNaN());
+ // The constructor will be added later, after DateObjectImp has been built.
+}
+
+bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticFunctionSlot<JSObject>(exec, &dateTable, this, propertyName, slot);
+}
+
+// ------------------------------ DateObjectImp --------------------------------
+
+// TODO: MakeTime (15.9.11.1) etc. ?
+
+DateObjectImp::DateObjectImp(ExecState* exec, FunctionPrototype* funcProto, DatePrototype* dateProto)
+ : InternalFunctionImp(funcProto, dateProto->classInfo()->className)
+{
+ static const Identifier* parsePropertyName = new Identifier("parse");
+ static const Identifier* UTCPropertyName = new Identifier("UTC");
+
+ putDirect(exec->propertyNames().prototype, dateProto, DontEnum|DontDelete|ReadOnly);
+ putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::Parse, 1, *parsePropertyName), DontEnum);
+ putDirectFunction(new DateObjectFuncImp(exec, funcProto, DateObjectFuncImp::UTC, 7, *UTCPropertyName), DontEnum);
+ putDirect(exec->propertyNames().length, 7, ReadOnly|DontDelete|DontEnum);
+}
+
+bool DateObjectImp::implementsConstruct() const
+{
+ return true;
+}
+
+// ECMA 15.9.3
+JSObject *DateObjectImp::construct(ExecState *exec, const List &args)
+{
+ int numArgs = args.size();
+
+ double value;
+
+ if (numArgs == 0) { // new Date() ECMA 15.9.3.3
+ value = getCurrentUTCTime();
+ } else if (numArgs == 1) {
+ if (args[0]->isObject(&DateInstance::info))
+ value = static_cast<DateInstance*>(args[0])->internalValue()->toNumber(exec);
+ else {
+ JSValue* primitive = args[0]->toPrimitive(exec);
+ if (primitive->isString())
+ value = parseDate(primitive->getString());
+ else
+ value = primitive->toNumber(exec);
+ }
+ } else {
+ if (isnan(args[0]->toNumber(exec))
+ || isnan(args[1]->toNumber(exec))
+ || (numArgs >= 3 && isnan(args[2]->toNumber(exec)))
+ || (numArgs >= 4 && isnan(args[3]->toNumber(exec)))
+ || (numArgs >= 5 && isnan(args[4]->toNumber(exec)))
+ || (numArgs >= 6 && isnan(args[5]->toNumber(exec)))
+ || (numArgs >= 7 && isnan(args[6]->toNumber(exec)))) {
+ value = NaN;
+ } else {
+ GregorianDateTime t;
+ int year = args[0]->toInt32(exec);
+ t.year = (year >= 0 && year <= 99) ? year : year - 1900;
+ t.month = args[1]->toInt32(exec);
+ t.monthDay = (numArgs >= 3) ? args[2]->toInt32(exec) : 1;
+ t.hour = args[3]->toInt32(exec);
+ t.minute = args[4]->toInt32(exec);
+ t.second = args[5]->toInt32(exec);
+ t.isDST = -1;
+ double ms = (numArgs >= 7) ? args[6]->toNumber(exec) : 0;
+ value = gregorianDateTimeToMS(t, ms, false);
+ }
+ }
+
+ DateInstance *ret = new DateInstance(exec->lexicalGlobalObject()->datePrototype());
+ ret->setInternalValue(jsNumber(timeClip(value)));
+ return ret;
+}
+
+// ECMA 15.9.2
+JSValue *DateObjectImp::callAsFunction(ExecState * /*exec*/, JSObject * /*thisObj*/, const List &/*args*/)
+{
+ time_t t = time(0);
+ GregorianDateTime ts(*localtime(&t));
+ return jsString(formatDate(ts) + " " + formatTime(ts, false));
+}
+
+// ------------------------------ DateObjectFuncImp ----------------------------
+
+DateObjectFuncImp::DateObjectFuncImp(ExecState* exec, FunctionPrototype* funcProto, int i, int len, const Identifier& name)
+ : InternalFunctionImp(funcProto, name), id(i)
+{
+ putDirect(exec->propertyNames().length, len, DontDelete|ReadOnly|DontEnum);
+}
+
+// ECMA 15.9.4.2 - 3
+JSValue *DateObjectFuncImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
+{
+ if (id == Parse) {
+ return jsNumber(parseDate(args[0]->toString(exec)));
+ }
+ else { // UTC
+ int n = args.size();
+ if (isnan(args[0]->toNumber(exec))
+ || isnan(args[1]->toNumber(exec))
+ || (n >= 3 && isnan(args[2]->toNumber(exec)))
+ || (n >= 4 && isnan(args[3]->toNumber(exec)))
+ || (n >= 5 && isnan(args[4]->toNumber(exec)))
+ || (n >= 6 && isnan(args[5]->toNumber(exec)))
+ || (n >= 7 && isnan(args[6]->toNumber(exec)))) {
+ return jsNaN();
+ }
+
+ GregorianDateTime t;
+ int year = args[0]->toInt32(exec);
+ t.year = (year >= 0 && year <= 99) ? year : year - 1900;
+ t.month = args[1]->toInt32(exec);
+ t.monthDay = (n >= 3) ? args[2]->toInt32(exec) : 1;
+ t.hour = args[3]->toInt32(exec);
+ t.minute = args[4]->toInt32(exec);
+ t.second = args[5]->toInt32(exec);
+ double ms = (n >= 7) ? args[6]->toNumber(exec) : 0;
+ return jsNumber(gregorianDateTimeToMS(t, ms, true));
+ }
+}
+
+// -----------------------------------------------------------------------------
+
+// Code originally from krfcdate.cpp, but we don't want to use kdecore, and we want double range.
+
+static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second)
+{
+ double days = (day - 32075)
+ + floor(1461 * (year + 4800.0 + (mon - 14) / 12) / 4)
+ + 367 * (mon - 2 - (mon - 14) / 12 * 12) / 12
+ - floor(3 * ((year + 4900.0 + (mon - 14) / 12) / 100) / 4)
+ - 2440588;
+ return ((days * hoursPerDay + hour) * minutesPerHour + minute) * secondsPerMinute + second;
+}
+
+// We follow the recommendation of RFC 2822 to consider all
+// obsolete time zones not listed here equivalent to "-0000".
+static const struct KnownZone {
+#if !PLATFORM(WIN_OS)
+ const
+#endif
+ char tzName[4];
+ int tzOffset;
+} known_zones[] = {
+ { "UT", 0 },
+ { "GMT", 0 },
+ { "EST", -300 },
+ { "EDT", -240 },
+ { "CST", -360 },
+ { "CDT", -300 },
+ { "MST", -420 },
+ { "MDT", -360 },
+ { "PST", -480 },
+ { "PDT", -420 }
+};
+
+inline static void skipSpacesAndComments(const char*& s)
+{
+ int nesting = 0;
+ char ch;
+ while ((ch = *s)) {
+ if (!isASCIISpace(ch)) {
+ if (ch == '(')
+ nesting++;
+ else if (ch == ')' && nesting > 0)
+ nesting--;
+ else if (nesting == 0)
+ break;
+ }
+ s++;
+ }
+}
+
+// returns 0-11 (Jan-Dec); -1 on failure
+static int findMonth(const char* monthStr)
+{
+ ASSERT(monthStr);
+ char needle[4];
+ for (int i = 0; i < 3; ++i) {
+ if (!*monthStr)
+ return -1;
+ needle[i] = static_cast<char>(toASCIILower(*monthStr++));
+ }
+ needle[3] = '\0';
+ const char *haystack = "janfebmaraprmayjunjulaugsepoctnovdec";
+ const char *str = strstr(haystack, needle);
+ if (str) {
+ int position = static_cast<int>(str - haystack);
+ if (position % 3 == 0)
+ return position / 3;
+ }
+ return -1;
+}
+
+static double parseDate(const UString &date)
+{
+ // This parses a date in the form:
+ // Tuesday, 09-Nov-99 23:12:40 GMT
+ // or
+ // Sat, 01-Jan-2000 08:00:00 GMT
+ // or
+ // Sat, 01 Jan 2000 08:00:00 GMT
+ // or
+ // 01 Jan 99 22:00 +0100 (exceptions in rfc822/rfc2822)
+ // ### non RFC formats, added for Javascript:
+ // [Wednesday] January 09 1999 23:12:40 GMT
+ // [Wednesday] January 09 23:12:40 GMT 1999
+ //
+ // We ignore the weekday.
+
+ CString dateCString = date.UTF8String();
+ const char *dateString = dateCString.c_str();
+
+ // Skip leading space
+ skipSpacesAndComments(dateString);
+
+ long month = -1;
+ const char *wordStart = dateString;
+ // Check contents of first words if not number
+ while (*dateString && !isASCIIDigit(*dateString)) {
+ if (isASCIISpace(*dateString) || *dateString == '(') {
+ if (dateString - wordStart >= 3)
+ month = findMonth(wordStart);
+ skipSpacesAndComments(dateString);
+ wordStart = dateString;
+ } else
+ dateString++;
+ }
+
+ // Missing delimiter between month and day (like "January29")?
+ if (month == -1 && wordStart != dateString)
+ month = findMonth(wordStart);
+
+ skipSpacesAndComments(dateString);
+
+ if (!*dateString)
+ return NaN;
+
+ // ' 09-Nov-99 23:12:40 GMT'
+ char *newPosStr;
+ errno = 0;
+ long day = strtol(dateString, &newPosStr, 10);
+ if (errno)
+ return NaN;
+ dateString = newPosStr;
+
+ if (!*dateString)
+ return NaN;
+
+ if (day < 0)
+ return NaN;
+
+ long year = 0;
+ if (day > 31) {
+ // ### where is the boundary and what happens below?
+ if (*dateString != '/')
+ return NaN;
+ // looks like a YYYY/MM/DD date
+ if (!*++dateString)
+ return NaN;
+ year = day;
+ month = strtol(dateString, &newPosStr, 10) - 1;
+ if (errno)
+ return NaN;
+ dateString = newPosStr;
+ if (*dateString++ != '/' || !*dateString)
+ return NaN;
+ day = strtol(dateString, &newPosStr, 10);
+ if (errno)
+ return NaN;
+ dateString = newPosStr;
+ } else if (*dateString == '/' && month == -1) {
+ dateString++;
+ // This looks like a MM/DD/YYYY date, not an RFC date.
+ month = day - 1; // 0-based
+ day = strtol(dateString, &newPosStr, 10);
+ if (errno)
+ return NaN;
+ if (day < 1 || day > 31)
+ return NaN;
+ dateString = newPosStr;
+ if (*dateString == '/')
+ dateString++;
+ if (!*dateString)
+ return NaN;
+ } else {
+ if (*dateString == '-')
+ dateString++;
+
+ skipSpacesAndComments(dateString);
+
+ if (*dateString == ',')
+ dateString++;
+
+ if (month == -1) { // not found yet
+ month = findMonth(dateString);
+ if (month == -1)
+ return NaN;
+
+ while (*dateString && *dateString != '-' && *dateString != ',' && !isASCIISpace(*dateString))
+ dateString++;
+
+ if (!*dateString)
+ return NaN;
+
+ // '-99 23:12:40 GMT'
+ if (*dateString != '-' && *dateString != '/' && *dateString != ',' && !isASCIISpace(*dateString))
+ return NaN;
+ dateString++;
+ }
+ }
+
+ if (month < 0 || month > 11)
+ return NaN;
+
+ // '99 23:12:40 GMT'
+ if (year <= 0 && *dateString) {
+ year = strtol(dateString, &newPosStr, 10);
+ if (errno)
+ return NaN;
+ }
+
+ // Don't fail if the time is missing.
+ long hour = 0;
+ long minute = 0;
+ long second = 0;
+ if (!*newPosStr)
+ dateString = newPosStr;
+ else {
+ // ' 23:12:40 GMT'
+ if (!(isASCIISpace(*newPosStr) || *newPosStr == ',')) {
+ if (*newPosStr != ':')
+ return NaN;
+ // There was no year; the number was the hour.
+ year = -1;
+ } else {
+ // in the normal case (we parsed the year), advance to the next number
+ dateString = ++newPosStr;
+ skipSpacesAndComments(dateString);
+ }
+
+ hour = strtol(dateString, &newPosStr, 10);
+ // Do not check for errno here since we want to continue
+ // even if errno was set becasue we are still looking
+ // for the timezone!
+
+ // Read a number? If not, this might be a timezone name.
+ if (newPosStr != dateString) {
+ dateString = newPosStr;
+
+ if (hour < 0 || hour > 23)
+ return NaN;
+
+ if (!*dateString)
+ return NaN;
+
+ // ':12:40 GMT'
+ if (*dateString++ != ':')
+ return NaN;
+
+ minute = strtol(dateString, &newPosStr, 10);
+ if (errno)
+ return NaN;
+ dateString = newPosStr;
+
+ if (minute < 0 || minute > 59)
+ return NaN;
+
+ // ':40 GMT'
+ if (*dateString && *dateString != ':' && !isASCIISpace(*dateString))
+ return NaN;
+
+ // seconds are optional in rfc822 + rfc2822
+ if (*dateString ==':') {
+ dateString++;
+
+ second = strtol(dateString, &newPosStr, 10);
+ if (errno)
+ return NaN;
+ dateString = newPosStr;
+
+ if (second < 0 || second > 59)
+ return NaN;
+ }
+
+ skipSpacesAndComments(dateString);
+
+ if (strncasecmp(dateString, "AM", 2) == 0) {
+ if (hour > 12)
+ return NaN;
+ if (hour == 12)
+ hour = 0;
+ dateString += 2;
+ skipSpacesAndComments(dateString);
+ } else if (strncasecmp(dateString, "PM", 2) == 0) {
+ if (hour > 12)
+ return NaN;
+ if (hour != 12)
+ hour += 12;
+ dateString += 2;
+ skipSpacesAndComments(dateString);
+ }
+ }
+ }
+
+ bool haveTZ = false;
+ int offset = 0;
+
+ // Don't fail if the time zone is missing.
+ // Some websites omit the time zone (4275206).
+ if (*dateString) {
+ if (strncasecmp(dateString, "GMT", 3) == 0 || strncasecmp(dateString, "UTC", 3) == 0) {
+ dateString += 3;
+ haveTZ = true;
+ }
+
+ if (*dateString == '+' || *dateString == '-') {
+ long o = strtol(dateString, &newPosStr, 10);
+ if (errno)
+ return NaN;
+ dateString = newPosStr;
+
+ if (o < -9959 || o > 9959)
+ return NaN;
+
+ int sgn = (o < 0) ? -1 : 1;
+ o = abs(o);
+ if (*dateString != ':') {
+ offset = ((o / 100) * 60 + (o % 100)) * sgn;
+ } else { // GMT+05:00
+ long o2 = strtol(dateString, &newPosStr, 10);
+ if (errno)
+ return NaN;
+ dateString = newPosStr;
+ offset = (o * 60 + o2) * sgn;
+ }
+ haveTZ = true;
+ } else {
+ for (int i = 0; i < int(sizeof(known_zones) / sizeof(KnownZone)); i++) {
+ if (0 == strncasecmp(dateString, known_zones[i].tzName, strlen(known_zones[i].tzName))) {
+ offset = known_zones[i].tzOffset;
+ dateString += strlen(known_zones[i].tzName);
+ haveTZ = true;
+ break;
+ }
+ }
+ }
+ }
+
+ skipSpacesAndComments(dateString);
+
+ if (*dateString && year == -1) {
+ year = strtol(dateString, &newPosStr, 10);
+ if (errno)
+ return NaN;
+ dateString = newPosStr;
+ }
+
+ skipSpacesAndComments(dateString);
+
+ // Trailing garbage
+ if (*dateString)
+ return NaN;
+
+ // Y2K: Handle 2 digit years.
+ if (year >= 0 && year < 100) {
+ if (year < 50)
+ year += 2000;
+ else
+ year += 1900;
+ }
+
+ // fall back to local timezone
+ if (!haveTZ) {
+ GregorianDateTime t;
+ t.monthDay = day;
+ t.month = month;
+ t.year = year - 1900;
+ t.isDST = -1;
+ t.second = second;
+ t.minute = minute;
+ t.hour = hour;
+
+ // Use our gregorianDateTimeToMS() rather than mktime() as the latter can't handle the full year range.
+ return gregorianDateTimeToMS(t, 0, false);
+ }
+
+ return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond;
+}
+
+double timeClip(double t)
+{
+ if (!isfinite(t))
+ return NaN;
+ if (fabs(t) > 8.64E15)
+ return NaN;
+ return trunc(t);
+}
+
+// Functions
+
+JSValue* dateProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsString("Invalid Date");
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsString(formatDate(t) + " " + formatTime(t, utc));
+}
+
+JSValue* dateProtoFuncToUTCString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = true;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsString("Invalid Date");
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc));
+}
+
+JSValue* dateProtoFuncToDateString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsString("Invalid Date");
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsString(formatDate(t));
+}
+
+JSValue* dateProtoFuncToTimeString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsString("Invalid Date");
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsString(formatTime(t, utc));
+}
+
+JSValue* dateProtoFuncToLocaleString(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsString("Invalid Date");
+
+#if PLATFORM(MAC)
+ double secs = floor(milli / msPerSecond);
+ return jsString(formatLocaleDate(exec, secs, true, true, args));
+#else
+ UNUSED_PARAM(args);
+
+ const bool utc = false;
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return formatLocaleDate(t, LocaleDateAndTime);
+#endif
+}
+
+JSValue* dateProtoFuncToLocaleDateString(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsString("Invalid Date");
+
+#if PLATFORM(MAC)
+ double secs = floor(milli / msPerSecond);
+ return jsString(formatLocaleDate(exec, secs, true, false, args));
+#else
+ UNUSED_PARAM(args);
+
+ const bool utc = false;
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return formatLocaleDate(t, LocaleDate);
+#endif
+}
+
+JSValue* dateProtoFuncToLocaleTimeString(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsString("Invalid Date");
+
+#if PLATFORM(MAC)
+ double secs = floor(milli / msPerSecond);
+ return jsString(formatLocaleDate(exec, secs, false, true, args));
+#else
+ UNUSED_PARAM(args);
+
+ const bool utc = false;
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return formatLocaleDate(t, LocaleTime);
+#endif
+}
+
+JSValue* dateProtoFuncValueOf(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ return jsNumber(milli);
+}
+
+JSValue* dateProtoFuncGetTime(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ return jsNumber(milli);
+}
+
+JSValue* dateProtoFuncGetFullYear(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(1900 + t.year);
+}
+
+JSValue* dateProtoFuncGetUTCFullYear(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = true;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(1900 + t.year);
+}
+
+JSValue* dateProtoFuncToGMTString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = true;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsString("Invalid Date");
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsString(formatDateUTCVariant(t) + " " + formatTime(t, utc));
+}
+
+JSValue* dateProtoFuncGetMonth(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.month);
+}
+
+JSValue* dateProtoFuncGetUTCMonth(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = true;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.month);
+}
+
+JSValue* dateProtoFuncGetDate(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.monthDay);
+}
+
+JSValue* dateProtoFuncGetUTCDate(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = true;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.monthDay);
+}
+
+JSValue* dateProtoFuncGetDay(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.weekDay);
+}
+
+JSValue* dateProtoFuncGetUTCDay(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = true;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.weekDay);
+}
+
+JSValue* dateProtoFuncGetHours(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.hour);
+}
+
+JSValue* dateProtoFuncGetUTCHours(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = true;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.hour);
+}
+
+JSValue* dateProtoFuncGetMinutes(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.minute);
+}
+
+JSValue* dateProtoFuncGetUTCMinutes(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = true;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.minute);
+}
+
+JSValue* dateProtoFuncGetSeconds(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.second);
+}
+
+JSValue* dateProtoFuncGetUTCSeconds(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = true;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(t.second);
+}
+
+JSValue* dateProtoFuncGetMilliSeconds(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ double secs = floor(milli / msPerSecond);
+ double ms = milli - secs * msPerSecond;
+ return jsNumber(ms);
+}
+
+JSValue* dateProtoFuncGetUTCMilliseconds(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ double secs = floor(milli / msPerSecond);
+ double ms = milli - secs * msPerSecond;
+ return jsNumber(ms);
+}
+
+JSValue* dateProtoFuncGetTimezoneOffset(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+ return jsNumber(-gmtoffset(t) / minutesPerHour);
+}
+
+JSValue* dateProtoFuncSetTime(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+
+ double milli = timeClip(args[0]->toNumber(exec));
+ JSValue* result = jsNumber(milli);
+ thisDateObj->setInternalValue(result);
+ return result;
+}
+
+static JSValue* setNewValueFromTimeArgs(ExecState* exec, JSObject* thisObj, const List& args, int numArgsToUse, bool inputIsUTC)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+
+ if (args.isEmpty() || isnan(milli)) {
+ JSValue* result = jsNaN();
+ thisDateObj->setInternalValue(result);
+ return result;
+ }
+
+ double secs = floor(milli / msPerSecond);
+ double ms = milli - secs * msPerSecond;
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, inputIsUTC, t);
+
+ if (!fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t)) {
+ JSValue* result = jsNaN();
+ thisDateObj->setInternalValue(result);
+ return result;
+ }
+
+ JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC));
+ thisDateObj->setInternalValue(result);
+ return result;
+}
+
+static JSValue* setNewValueFromDateArgs(ExecState* exec, JSObject* thisObj, const List& args, int numArgsToUse, bool inputIsUTC)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ if (args.isEmpty()) {
+ JSValue* result = jsNaN();
+ thisDateObj->setInternalValue(result);
+ return result;
+ }
+
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ double ms = 0;
+
+ GregorianDateTime t;
+ if (numArgsToUse == 3 && isnan(milli))
+ // Based on ECMA 262 15.9.5.40 - .41 (set[UTC]FullYear)
+ // the time must be reset to +0 if it is NaN.
+ msToGregorianDateTime(0, true, t);
+ else {
+ double secs = floor(milli / msPerSecond);
+ ms = milli - secs * msPerSecond;
+ msToGregorianDateTime(milli, inputIsUTC, t);
+ }
+
+ if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t)) {
+ JSValue* result = jsNaN();
+ thisDateObj->setInternalValue(result);
+ return result;
+ }
+
+ JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, inputIsUTC));
+ thisDateObj->setInternalValue(result);
+ return result;
+}
+
+JSValue* dateProtoFuncSetMilliSeconds(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromTimeArgs(exec, thisObj, args, 1, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetUTCMilliseconds(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromTimeArgs(exec, thisObj, args, 1, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetSeconds(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromTimeArgs(exec, thisObj, args, 2, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetUTCSeconds(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromTimeArgs(exec, thisObj, args, 2, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetMinutes(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromTimeArgs(exec, thisObj, args, 3, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetUTCMinutes(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromTimeArgs(exec, thisObj, args, 3, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetHours(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromTimeArgs(exec, thisObj, args, 4, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetUTCHours(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromTimeArgs(exec, thisObj, args, 4, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetDate(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromDateArgs(exec, thisObj, args, 1, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetUTCDate(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromDateArgs(exec, thisObj, args, 1, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetMonth(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromDateArgs(exec, thisObj, args, 2, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetUTCMonth(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromDateArgs(exec, thisObj, args, 2, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetFullYear(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = false;
+ return setNewValueFromDateArgs(exec, thisObj, args, 3, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetUTCFullYear(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ const bool inputIsUTC = true;
+ return setNewValueFromDateArgs(exec, thisObj, args, 3, inputIsUTC);
+}
+
+JSValue* dateProtoFuncSetYear(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ if (args.isEmpty()) {
+ JSValue* result = jsNaN();
+ thisDateObj->setInternalValue(result);
+ return result;
+ }
+
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ double ms = 0;
+
+ GregorianDateTime t;
+ if (isnan(milli))
+ // Based on ECMA 262 B.2.5 (setYear)
+ // the time must be reset to +0 if it is NaN.
+ msToGregorianDateTime(0, true, t);
+ else {
+ double secs = floor(milli / msPerSecond);
+ ms = milli - secs * msPerSecond;
+ msToGregorianDateTime(milli, utc, t);
+ }
+
+ bool ok = true;
+ int32_t year = args[0]->toInt32(exec, ok);
+ if (!ok) {
+ JSValue* result = jsNaN();
+ thisDateObj->setInternalValue(result);
+ return result;
+ }
+
+ t.year = (year > 99 || year < 0) ? year - 1900 : year;
+ JSValue* result = jsNumber(gregorianDateTimeToMS(t, ms, utc));
+ thisDateObj->setInternalValue(result);
+ return result;
+}
+
+JSValue* dateProtoFuncGetYear(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&DateInstance::info))
+ return throwError(exec, TypeError);
+
+ const bool utc = false;
+
+ DateInstance* thisDateObj = static_cast<DateInstance*>(thisObj);
+ JSValue* v = thisDateObj->internalValue();
+ double milli = v->toNumber(exec);
+ if (isnan(milli))
+ return jsNaN();
+
+ GregorianDateTime t;
+ msToGregorianDateTime(milli, utc, t);
+
+ // NOTE: IE returns the full year even in getYear.
+ return jsNumber(t.year);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/date_object.h b/JavaScriptCore/kjs/date_object.h
new file mode 100644
index 0000000..c545980
--- /dev/null
+++ b/JavaScriptCore/kjs/date_object.h
@@ -0,0 +1,135 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef DATE_OBJECT_H
+#define DATE_OBJECT_H
+
+#include "function.h"
+#include "JSWrapperObject.h"
+#include "lookup.h"
+
+namespace KJS {
+
+ struct GregorianDateTime;
+
+ class FunctionPrototype;
+ class ObjectPrototype;
+
+ class DateInstance : public JSWrapperObject {
+ public:
+ DateInstance(JSObject *proto);
+
+ bool getTime(GregorianDateTime&, int& offset) const;
+ bool getUTCTime(GregorianDateTime&) const;
+ bool getTime(double& milli, int& offset) const;
+ bool getUTCTime(double& milli) const;
+
+ virtual const ClassInfo *classInfo() const { return &info; }
+ static const ClassInfo info;
+ };
+
+ /**
+ * @internal
+ *
+ * The initial value of Date.prototype (and thus all objects created
+ * with the Date constructor
+ */
+ class DatePrototype : public DateInstance {
+ public:
+ DatePrototype(ExecState *, ObjectPrototype *);
+ virtual bool getOwnPropertySlot(ExecState *, const Identifier &, PropertySlot&);
+ virtual const ClassInfo *classInfo() const { return &info; }
+ static const ClassInfo info;
+ };
+
+ /**
+ * @internal
+ *
+ * Functions to implement all methods that are properties of the
+ * Date.prototype object
+ */
+
+ // Non-normative properties (Appendix B)
+ // GetYear, SetYear, ToGMTString
+
+ JSValue* dateProtoFuncToString(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncToUTCString(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncToDateString(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncToTimeString(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncToLocaleString(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncToLocaleDateString(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncToLocaleTimeString(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncValueOf(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetTime(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetFullYear(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetUTCFullYear(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncToGMTString(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetMonth(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetUTCMonth(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetDate(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetUTCDate(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetDay(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetUTCDay(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetHours(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetUTCHours(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetMinutes(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetUTCMinutes(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetSeconds(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetUTCSeconds(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetMilliSeconds(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetUTCMilliseconds(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetTimezoneOffset(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetTime(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetMilliSeconds(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetUTCMilliseconds(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetSeconds(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetUTCSeconds(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetMinutes(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetUTCMinutes(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetHours(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetUTCHours(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetDate(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetUTCDate(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetMonth(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetUTCMonth(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetFullYear(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetUTCFullYear(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncSetYear(ExecState*, JSObject*, const List&);
+ JSValue* dateProtoFuncGetYear(ExecState*, JSObject*, const List&);
+
+ /**
+ * @internal
+ *
+ * The initial value of the the global variable's "Date" property
+ */
+ class DateObjectImp : public InternalFunctionImp {
+ public:
+ DateObjectImp(ExecState *, FunctionPrototype *, DatePrototype *);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject *construct(ExecState *, const List &args);
+ virtual JSValue *callAsFunction(ExecState *, JSObject *thisObj, const List &args);
+
+ JSObject *construct(const List &);
+ };
+
+} // namespace
+
+#endif
diff --git a/JavaScriptCore/kjs/debugger.cpp b/JavaScriptCore/kjs/debugger.cpp
new file mode 100644
index 0000000..af9c5fa
--- /dev/null
+++ b/JavaScriptCore/kjs/debugger.cpp
@@ -0,0 +1,134 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.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 "debugger.h"
+
+#include "JSGlobalObject.h"
+#include "internal.h"
+#include "ustring.h"
+
+using namespace KJS;
+
+// ------------------------------ Debugger -------------------------------------
+
+namespace KJS {
+ struct AttachedGlobalObject
+ {
+ public:
+ AttachedGlobalObject(JSGlobalObject* o, AttachedGlobalObject* ai) : globalObj(o), next(ai) { ++Debugger::debuggersPresent; }
+ ~AttachedGlobalObject() { --Debugger::debuggersPresent; }
+ JSGlobalObject* globalObj;
+ AttachedGlobalObject* next;
+ };
+
+}
+
+int Debugger::debuggersPresent = 0;
+
+Debugger::Debugger()
+{
+ rep = new DebuggerImp();
+}
+
+Debugger::~Debugger()
+{
+ detach(0);
+ delete rep;
+}
+
+void Debugger::attach(JSGlobalObject* globalObject)
+{
+ Debugger* other = globalObject->debugger();
+ if (other == this)
+ return;
+ if (other)
+ other->detach(globalObject);
+ globalObject->setDebugger(this);
+ rep->globalObjects = new AttachedGlobalObject(globalObject, rep->globalObjects);
+}
+
+void Debugger::detach(JSGlobalObject* globalObj)
+{
+ // iterate the addresses where AttachedGlobalObject pointers are stored
+ // so we can unlink items from the list
+ AttachedGlobalObject **p = &rep->globalObjects;
+ AttachedGlobalObject *q;
+ while ((q = *p)) {
+ if (!globalObj || q->globalObj == globalObj) {
+ *p = q->next;
+ q->globalObj->setDebugger(0);
+ delete q;
+ } else
+ p = &q->next;
+ }
+
+ if (globalObj)
+ latestExceptions.remove(globalObj);
+ else
+ latestExceptions.clear();
+}
+
+bool Debugger::hasHandledException(ExecState *exec, JSValue *exception)
+{
+ if (latestExceptions.get(exec->dynamicGlobalObject()).get() == exception)
+ return true;
+
+ latestExceptions.set(exec->dynamicGlobalObject(), exception);
+ return false;
+}
+
+bool Debugger::sourceParsed(ExecState*, int /*sourceId*/, const UString &/*sourceURL*/,
+ const UString &/*source*/, int /*startingLineNumber*/, int /*errorLine*/, const UString & /*errorMsg*/)
+{
+ return true;
+}
+
+bool Debugger::sourceUnused(ExecState*, int /*sourceId*/)
+{
+ return true;
+}
+
+bool Debugger::exception(ExecState*, int /*sourceId*/, int /*lineno*/,
+ JSValue* /*exception */)
+{
+ return true;
+}
+
+bool Debugger::atStatement(ExecState*, int /*sourceId*/, int /*firstLine*/,
+ int /*lastLine*/)
+{
+ return true;
+}
+
+bool Debugger::callEvent(ExecState*, int /*sourceId*/, int /*lineno*/,
+ JSObject* /*function*/, const List &/*args*/)
+{
+ return true;
+}
+
+bool Debugger::returnEvent(ExecState*, int /*sourceId*/, int /*lineno*/,
+ JSObject* /*function*/)
+{
+ return true;
+}
+
diff --git a/JavaScriptCore/kjs/debugger.h b/JavaScriptCore/kjs/debugger.h
new file mode 100644
index 0000000..2d5cb6f
--- /dev/null
+++ b/JavaScriptCore/kjs/debugger.h
@@ -0,0 +1,225 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef _KJSDEBUGGER_H_
+#define _KJSDEBUGGER_H_
+
+#include <wtf/HashMap.h>
+#include "protect.h"
+
+namespace KJS {
+
+ class DebuggerImp;
+ class ExecState;
+ class JSGlobalObject;
+ class JSObject;
+ class JSValue;
+ class UString;
+ class List;
+
+ /**
+ * @internal
+ *
+ * Provides an interface which receives notification about various
+ * script-execution related events such as statement execution and function
+ * calls.
+ *
+ * WARNING: This interface is still a work in progress and is not yet
+ * offically publicly available. It is likely to change in binary incompatible
+ * (and possibly source incompatible) ways in future versions. It is
+ * anticipated that at some stage the interface will be frozen and made
+ * available for general use.
+ */
+ class Debugger {
+ public:
+
+ /**
+ * Creates a new debugger
+ */
+ Debugger();
+
+ /**
+ * Destroys the debugger. If the debugger is attached to any global objects,
+ * it is automatically detached.
+ */
+ virtual ~Debugger();
+
+ DebuggerImp *imp() const { return rep; }
+
+ /**
+ * Attaches the debugger to specified global object. This will cause this
+ * object to receive notification of events during execution.
+ *
+ * If the global object is deleted, it will detach the debugger.
+ *
+ * Note: only one debugger can be attached to a global object at a time.
+ * Attaching another debugger to the same global object will cause the
+ * original debugger to be detached.
+ *
+ * @param The global object to attach to.
+ *
+ * @see detach()
+ */
+ void attach(JSGlobalObject*);
+
+ /**
+ * Detach the debugger from a global object.
+ *
+ * @param The global object to detach from. If 0, the debugger will be
+ * detached from all global objects to which it is attached.
+ *
+ * @see attach()
+ */
+ void detach(JSGlobalObject*);
+
+ /**
+ * Called to notify the debugger that some javascript source code has
+ * been parsed. For calls to Interpreter::evaluate(), this will be called
+ * with the supplied source code before any other code is parsed.
+ * Other situations in which this may be called include creation of a
+ * function using the Function() constructor, or the eval() function.
+ *
+ * The default implementation does nothing. Override this method if
+ * you want to process this event.
+ *
+ * @param exec The current execution state
+ * @param sourceId The ID of the source code (corresponds to the
+ * sourceId supplied in other functions such as atStatement()
+ * @param sourceURL Where the source code that was parsed came from
+ * @param source The source code that was parsed
+ * @param startingLineNumber The line number at which parsing started
+ * @param errorLine The line number at which parsing encountered an
+ * error, or -1 if the source code was valid and parsed successfully
+ * @param errorMsg The error description, or null if the source code
+ was valid and parsed successfully
+ * @return true if execution should be continue, false if it should
+ * be aborted
+ */
+ virtual bool sourceParsed(ExecState *exec, int sourceId, const UString &sourceURL,
+ const UString &source, int startingLineNumber, int errorLine, const UString &errorMsg);
+
+ /**
+ * Called when all functions/programs associated with a particular
+ * sourceId have been deleted. After this function has been called for
+ * a particular sourceId, that sourceId will not be used again.
+ *
+ * The default implementation does nothing. Override this method if
+ * you want to process this event.
+ *
+ * @param exec The current execution state
+ * @param sourceId The ID of the source code (corresponds to the
+ * sourceId supplied in other functions such as atLine()
+ * @return true if execution should be continue, false if it should
+ * be aborted
+ */
+ virtual bool sourceUnused(ExecState *exec, int sourceId);
+
+ /**
+ * Called when an exception is thrown during script execution.
+ *
+ * The default implementation does nothing. Override this method if
+ * you want to process this event.
+ *
+ * @param exec The current execution state
+ * @param sourceId The ID of the source code being executed
+ * @param lineno The line at which the error occurred
+ * @param exceptionObj The exception object
+ * @return true if execution should be continue, false if it should
+ * be aborted
+ */
+ virtual bool exception(ExecState *exec, int sourceId, int lineno,
+ JSValue *exception);
+
+ bool hasHandledException(ExecState *, JSValue *);
+
+ /**
+ * Called when a line of the script is reached (before it is executed)
+ *
+ * The default implementation does nothing. Override this method if
+ * you want to process this event.
+ *
+ * @param exec The current execution state
+ * @param sourceId The ID of the source code being executed
+ * @param firstLine The starting line of the statement that is about to be
+ * executed
+ * @param lastLine The ending line of the statement that is about to be
+ * executed (usually the same as firstLine)
+ * @return true if execution should be continue, false if it should
+ * be aborted
+ */
+ virtual bool atStatement(ExecState *exec, int sourceId, int firstLine,
+ int lastLine);
+ /**
+ * Called on each function call. Use together with @ref #returnEvent
+ * if you want to keep track of the call stack.
+ *
+ * Note: This only gets called for functions that are declared in ECMAScript
+ * source code or passed to eval(), not for internal KJS or
+ * application-supplied functions.
+ *
+ * The default implementation does nothing. Override this method if
+ * you want to process this event.
+ *
+ * @param exec The current execution state
+ * @param sourceId The ID of the source code being executed
+ * @param lineno The line that is about to be executed
+ * @param function The function being called
+ * @param args The arguments that were passed to the function
+ * line is being executed
+ * @return true if execution should be continue, false if it should
+ * be aborted
+ */
+ virtual bool callEvent(ExecState *exec, int sourceId, int lineno,
+ JSObject *function, const List &args);
+
+ /**
+ * Called on each function exit. The function being returned from is that
+ * which was supplied in the last callEvent().
+ *
+ * Note: This only gets called for functions that are declared in ECMAScript
+ * source code or passed to eval(), not for internal KJS or
+ * application-supplied functions.
+ *
+ * The default implementation does nothing. Override this method if
+ * you want to process this event.
+ *
+ * @param exec The current execution state
+ * @param sourceId The ID of the source code being executed
+ * @param lineno The line that is about to be executed
+ * @param function The function being called
+ * @return true if execution should be continue, false if it should
+ * be aborted
+ */
+ virtual bool returnEvent(ExecState *exec, int sourceId, int lineno,
+ JSObject *function);
+
+ private:
+ DebuggerImp *rep;
+ HashMap<JSGlobalObject*, ProtectedPtr<JSValue> > latestExceptions;
+
+ public:
+ static int debuggersPresent;
+ };
+
+}
+
+#endif
diff --git a/JavaScriptCore/kjs/dtoa.cpp b/JavaScriptCore/kjs/dtoa.cpp
new file mode 100644
index 0000000..a8e3a68
--- /dev/null
+++ b/JavaScriptCore/kjs/dtoa.cpp
@@ -0,0 +1,3300 @@
+/****************************************************************
+ *
+ * The author of this software is David M. Gay.
+ *
+ * Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ *
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHOR NOR LUCENT MAKES ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ *
+ ***************************************************************/
+
+/* Please send bug reports to
+ David M. Gay
+ Bell Laboratories, Room 2C-463
+ 600 Mountain Avenue
+ Murray Hill, NJ 07974-0636
+ U.S.A.
+ dmg@bell-labs.com
+ */
+
+/* On a machine with IEEE extended-precision registers, it is
+ * necessary to specify double-precision (53-bit) rounding precision
+ * before invoking strtod or dtoa. If the machine uses (the equivalent
+ * of) Intel 80x87 arithmetic, the call
+ * _control87(PC_53, MCW_PC);
+ * does this with many compilers. Whether this or another call is
+ * appropriate depends on the compiler; for this to work, it may be
+ * necessary to #include "float.h" or another system-dependent header
+ * file.
+ */
+
+/* strtod for IEEE-, VAX-, and IBM-arithmetic machines.
+ *
+ * This strtod returns a nearest machine number to the input decimal
+ * string (or sets errno to ERANGE). With IEEE arithmetic, ties are
+ * broken by the IEEE round-even rule. Otherwise ties are broken by
+ * biased rounding (add half and chop).
+ *
+ * Inspired loosely by William D. Clinger's paper "How to Read Floating
+ * Point Numbers Accurately" [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ *
+ * 1. We only require IEEE, IBM, or VAX double-precision
+ * arithmetic (not IEEE double-extended).
+ * 2. We get by with floating-point arithmetic in a case that
+ * Clinger missed -- when we're computing d * 10^n
+ * for a small integer d and the integer n is not too
+ * much larger than 22 (the maximum integer k for which
+ * we can represent 10^k exactly), we may be able to
+ * compute (d*10^k) * 10^(e-k) with just one roundoff.
+ * 3. Rather than a bit-at-a-time adjustment of the binary
+ * result in the hard case, we use floating-point
+ * arithmetic to determine the adjustment to within
+ * one bit; only in really hard cases do we need to
+ * compute a second residual.
+ * 4. Because of 3., we don't need a large table of powers of 10
+ * for ten-to-e (just some small tables, e.g. of 10^k
+ * for 0 <= k <= 22).
+ */
+
+/*
+ * #define IEEE_8087 for IEEE-arithmetic machines where the least
+ * significant byte has the lowest address.
+ * #define IEEE_MC68k for IEEE-arithmetic machines where the most
+ * significant byte has the lowest address.
+ * #define Long int on machines with 32-bit ints and 64-bit longs.
+ * #define IBM for IBM mainframe-style floating-point arithmetic.
+ * #define VAX for VAX-style floating-point arithmetic (D_floating).
+ * #define No_leftright to omit left-right logic in fast floating-point
+ * computation of dtoa.
+ * #define Honor_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ * and strtod and dtoa should round accordingly.
+ * #define Check_FLT_ROUNDS if FLT_ROUNDS can assume the values 2 or 3
+ * and Honor_FLT_ROUNDS is not #defined.
+ * #define RND_PRODQUOT to use rnd_prod and rnd_quot (assembly routines
+ * that use extended-precision instructions to compute rounded
+ * products and quotients) with IBM.
+ * #define ROUND_BIASED for IEEE-format with biased rounding.
+ * #define Inaccurate_Divide for IEEE-format with correctly rounded
+ * products but inaccurate quotients, e.g., for Intel i860.
+ * #define NO_LONG_LONG on machines that do not have a "long long"
+ * integer type (of >= 64 bits). On such machines, you can
+ * #define Just_16 to store 16 bits per 32-bit Long when doing
+ * high-precision integer arithmetic. Whether this speeds things
+ * up or slows things down depends on the machine and the number
+ * being converted. If long long is available and the name is
+ * something other than "long long", #define Llong to be the name,
+ * and if "unsigned Llong" does not work as an unsigned version of
+ * Llong, #define #ULLong to be the corresponding unsigned type.
+ * #define KR_headers for old-style C function headers.
+ * #define Bad_float_h if your system lacks a float.h or if it does not
+ * define some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ * FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
+ * #define MALLOC your_malloc, where your_malloc(n) acts like malloc(n)
+ * if memory is available and otherwise does something you deem
+ * appropriate. If MALLOC is undefined, malloc will be invoked
+ * directly -- and assumed always to succeed.
+ * #define Omit_Private_Memory to omit logic (added Jan. 1998) for making
+ * memory allocations from a private pool of memory when possible.
+ * When used, the private pool is PRIVATE_MEM bytes long: 2304 bytes,
+ * unless #defined to be a different length. This default length
+ * suffices to get rid of MALLOC calls except for unusual cases,
+ * such as decimal-to-binary conversion of a very long string of
+ * digits. The longest string dtoa can return is about 751 bytes
+ * long. For conversions by strtod of strings of 800 digits and
+ * all dtoa conversions in single-threaded executions with 8-byte
+ * pointers, PRIVATE_MEM >= 7400 appears to suffice; with 4-byte
+ * pointers, PRIVATE_MEM >= 7112 appears adequate.
+ * #define INFNAN_CHECK on IEEE systems to cause strtod to check for
+ * Infinity and NaN (case insensitively). On some systems (e.g.,
+ * some HP systems), it may be necessary to #define NAN_WORD0
+ * appropriately -- to the most significant word of a quiet NaN.
+ * (On HP Series 700/800 machines, -DNAN_WORD0=0x7ff40000 works.)
+ * When INFNAN_CHECK is #defined and No_Hex_NaN is not #defined,
+ * strtod also accepts (case insensitively) strings of the form
+ * NaN(x), where x is a string of hexadecimal digits and spaces;
+ * if there is only one string of hexadecimal digits, it is taken
+ * for the 52 fraction bits of the resulting NaN; if there are two
+ * or more strings of hex digits, the first is for the high 20 bits,
+ * the second and subsequent for the low 32 bits, with intervening
+ * white space ignored; but if this results in none of the 52
+ * fraction bits being on (an IEEE Infinity symbol), then NAN_WORD0
+ * and NAN_WORD1 are used instead.
+ * #define MULTIPLE_THREADS if the system offers preemptively scheduled
+ * multiple threads. In this case, you must provide (or suitably
+ * #define) two locks, acquired by ACQUIRE_DTOA_LOCK(n) and freed
+ * by FREE_DTOA_LOCK(n) for n = 0 or 1. (The second lock, accessed
+ * in pow5mult, ensures lazy evaluation of only one copy of high
+ * powers of 5; omitting this lock would introduce a small
+ * probability of wasting memory, but would otherwise be harmless.)
+ * You must also invoke freedtoa(s) to free the value s returned by
+ * dtoa. You may do so whether or not MULTIPLE_THREADS is #defined.
+ * #define NO_IEEE_Scale to disable new (Feb. 1997) logic in strtod that
+ * avoids underflows on inputs whose result does not underflow.
+ * If you #define NO_IEEE_Scale on a machine that uses IEEE-format
+ * floating-point numbers and flushes underflows to zero rather
+ * than implementing gradual underflow, then you must also #define
+ * Sudden_Underflow.
+ * #define YES_ALIAS to permit aliasing certain double values with
+ * arrays of ULongs. This leads to slightly better code with
+ * some compilers and was always used prior to 19990916, but it
+ * is not strictly legal and can cause trouble with aggressively
+ * optimizing compilers (e.g., gcc 2.95.1 under -O2).
+ * #define SET_INEXACT if IEEE arithmetic is being used and extra
+ * computation should be done to set the inexact flag when the
+ * result is inexact and avoid setting inexact when the result
+ * is exact. In this case, dtoa.c must be compiled in
+ * an environment, perhaps provided by #include "dtoa.c" in a
+ * suitable wrapper, that defines two functions,
+ * int get_inexact(void);
+ * void clear_inexact(void);
+ * such that get_inexact() returns a nonzero value if the
+ * inexact bit is already set, and clear_inexact() sets the
+ * inexact bit to 0. When SET_INEXACT is #defined, strtod
+ * also does extra computations to set the underflow and overflow
+ * flags when appropriate (i.e., when the result is tiny and
+ * inexact or when it is a numeric value rounded to +-infinity).
+ * #define NO_ERRNO if strtod should not assign errno = ERANGE when
+ * the result overflows to +-Infinity or underflows to 0.
+ */
+
+#include "config.h"
+#include "dtoa.h"
+
+#if COMPILER(MSVC)
+#pragma warning(disable: 4244)
+#pragma warning(disable: 4245)
+#pragma warning(disable: 4554)
+#endif
+
+#if PLATFORM(BIG_ENDIAN)
+#define IEEE_MC68k
+#else
+#define IEEE_8087
+#endif
+#define INFNAN_CHECK
+
+
+
+#ifndef Long
+#define Long int
+#endif
+#ifndef ULong
+typedef unsigned Long ULong;
+#endif
+
+#ifdef DEBUG
+#include <stdio.h>
+#define Bug(x) {fprintf(stderr, "%s\n", x); exit(1);}
+#endif
+
+#include <stdlib.h>
+#include <string.h>
+
+#ifdef MALLOC
+#ifdef KR_headers
+extern char *MALLOC();
+#else
+extern void *MALLOC(size_t);
+#endif
+#else
+#define MALLOC malloc
+#endif
+
+#ifndef Omit_Private_Memory
+#ifndef PRIVATE_MEM
+#define PRIVATE_MEM 2304
+#endif
+#define PRIVATE_mem ((PRIVATE_MEM+sizeof(double)-1)/sizeof(double))
+static double private_mem[PRIVATE_mem], *pmem_next = private_mem;
+#endif
+
+#undef IEEE_Arith
+#undef Avoid_Underflow
+#ifdef IEEE_MC68k
+#define IEEE_Arith
+#endif
+#ifdef IEEE_8087
+#define IEEE_Arith
+#endif
+
+#include <errno.h>
+
+#ifdef Bad_float_h
+
+#ifdef IEEE_Arith
+#define DBL_DIG 15
+#define DBL_MAX_10_EXP 308
+#define DBL_MAX_EXP 1024
+#define FLT_RADIX 2
+#endif /*IEEE_Arith*/
+
+#ifdef IBM
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 75
+#define DBL_MAX_EXP 63
+#define FLT_RADIX 16
+#define DBL_MAX 7.2370055773322621e+75
+#endif
+
+#ifdef VAX
+#define DBL_DIG 16
+#define DBL_MAX_10_EXP 38
+#define DBL_MAX_EXP 127
+#define FLT_RADIX 2
+#define DBL_MAX 1.7014118346046923e+38
+#endif
+
+#ifndef LONG_MAX
+#define LONG_MAX 2147483647
+#endif
+
+#else /* ifndef Bad_float_h */
+#include <float.h>
+#endif /* Bad_float_h */
+
+#ifndef __MATH_H__
+#include <math.h>
+#endif
+
+#define strtod kjs_strtod
+#define dtoa kjs_dtoa
+#define freedtoa kjs_freedtoa
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef CONST_
+#ifdef KR_headers
+#define CONST_ /* blank */
+#else
+#define CONST_ const
+#endif
+#endif
+
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(VAX) + defined(IBM) != 1
+Exactly one of IEEE_8087, IEEE_MC68k, VAX, or IBM should be defined.
+#endif
+
+typedef union { double d; ULong L[2]; } U;
+
+#ifdef YES_ALIAS
+#define dval(x) x
+#ifdef IEEE_8087
+#define word0(x) ((ULong *)&x)[1]
+#define word1(x) ((ULong *)&x)[0]
+#else
+#define word0(x) ((ULong *)&x)[0]
+#define word1(x) ((ULong *)&x)[1]
+#endif
+#else
+#ifdef IEEE_8087
+#define word0(x) ((U*)&x)->L[1]
+#define word1(x) ((U*)&x)->L[0]
+#else
+#define word0(x) ((U*)&x)->L[0]
+#define word1(x) ((U*)&x)->L[1]
+#endif
+#define dval(x) ((U*)&x)->d
+#endif
+
+/* The following definition of Storeinc is appropriate for MIPS processors.
+ * An alternative that might be better on some machines is
+ * #define Storeinc(a,b,c) (*a++ = b << 16 | c & 0xffff)
+ */
+#if defined(IEEE_8087) + defined(VAX)
+#define Storeinc(a,b,c) (((unsigned short *)a)[1] = (unsigned short)b, \
+((unsigned short *)a)[0] = (unsigned short)c, a++)
+#else
+#define Storeinc(a,b,c) (((unsigned short *)a)[0] = (unsigned short)b, \
+((unsigned short *)a)[1] = (unsigned short)c, a++)
+#endif
+
+/* #define P DBL_MANT_DIG */
+/* Ten_pmax = floor(P*log(2)/log(5)) */
+/* Bletch = (highest power of 2 < DBL_MAX_10_EXP) / 16 */
+/* Quick_max = floor((P-1)*log(FLT_RADIX)/log(10) - 1) */
+/* Int_max = floor(P*log(FLT_RADIX)/log(10) - 1) */
+
+#ifdef IEEE_Arith
+#define Exp_shift 20
+#define Exp_shift1 20
+#define Exp_msk1 0x100000
+#define Exp_msk11 0x100000
+#define Exp_mask 0x7ff00000
+#define P 53
+#define Bias 1023
+#define Emin (-1022)
+#define Exp_1 0x3ff00000
+#define Exp_11 0x3ff00000
+#define Ebits 11
+#define Frac_mask 0xfffff
+#define Frac_mask1 0xfffff
+#define Ten_pmax 22
+#define Bletch 0x10
+#define Bndry_mask 0xfffff
+#define Bndry_mask1 0xfffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 1
+#define Tiny0 0
+#define Tiny1 1
+#define Quick_max 14
+#define Int_max 14
+#ifndef NO_IEEE_Scale
+#define Avoid_Underflow
+#ifdef Flush_Denorm /* debugging option */
+#undef Sudden_Underflow
+#endif
+#endif
+
+#ifndef Flt_Rounds
+#ifdef FLT_ROUNDS
+#define Flt_Rounds FLT_ROUNDS
+#else
+#define Flt_Rounds 1
+#endif
+#endif /*Flt_Rounds*/
+
+#ifdef Honor_FLT_ROUNDS
+#define Rounding rounding
+#undef Check_FLT_ROUNDS
+#define Check_FLT_ROUNDS
+#else
+#define Rounding Flt_Rounds
+#endif
+
+#else /* ifndef IEEE_Arith */
+#undef Check_FLT_ROUNDS
+#undef Honor_FLT_ROUNDS
+#undef SET_INEXACT
+#undef Sudden_Underflow
+#define Sudden_Underflow
+#ifdef IBM
+#undef Flt_Rounds
+#define Flt_Rounds 0
+#define Exp_shift 24
+#define Exp_shift1 24
+#define Exp_msk1 0x1000000
+#define Exp_msk11 0x1000000
+#define Exp_mask 0x7f000000
+#define P 14
+#define Bias 65
+#define Exp_1 0x41000000
+#define Exp_11 0x41000000
+#define Ebits 8 /* exponent has 7 bits, but 8 is the right value in b2d */
+#define Frac_mask 0xffffff
+#define Frac_mask1 0xffffff
+#define Bletch 4
+#define Ten_pmax 22
+#define Bndry_mask 0xefffff
+#define Bndry_mask1 0xffffff
+#define LSB 1
+#define Sign_bit 0x80000000
+#define Log2P 4
+#define Tiny0 0x100000
+#define Tiny1 0
+#define Quick_max 14
+#define Int_max 15
+#else /* VAX */
+#undef Flt_Rounds
+#define Flt_Rounds 1
+#define Exp_shift 23
+#define Exp_shift1 7
+#define Exp_msk1 0x80
+#define Exp_msk11 0x800000
+#define Exp_mask 0x7f80
+#define P 56
+#define Bias 129
+#define Exp_1 0x40800000
+#define Exp_11 0x4080
+#define Ebits 8
+#define Frac_mask 0x7fffff
+#define Frac_mask1 0xffff007f
+#define Ten_pmax 24
+#define Bletch 2
+#define Bndry_mask 0xffff007f
+#define Bndry_mask1 0xffff007f
+#define LSB 0x10000
+#define Sign_bit 0x8000
+#define Log2P 1
+#define Tiny0 0x80
+#define Tiny1 0
+#define Quick_max 15
+#define Int_max 15
+#endif /* IBM, VAX */
+#endif /* IEEE_Arith */
+
+#ifndef IEEE_Arith
+#define ROUND_BIASED
+#endif
+
+#ifdef RND_PRODQUOT
+#define rounded_product(a,b) a = rnd_prod(a, b)
+#define rounded_quotient(a,b) a = rnd_quot(a, b)
+#ifdef KR_headers
+extern double rnd_prod(), rnd_quot();
+#else
+extern double rnd_prod(double, double), rnd_quot(double, double);
+#endif
+#else
+#define rounded_product(a,b) a *= b
+#define rounded_quotient(a,b) a /= b
+#endif
+
+#define Big0 (Frac_mask1 | Exp_msk1*(DBL_MAX_EXP+Bias-1))
+#define Big1 0xffffffff
+
+#ifndef Pack_32
+#define Pack_32
+#endif
+
+#ifdef KR_headers
+#define FFFFFFFF ((((unsigned long)0xffff)<<16)|(unsigned long)0xffff)
+#else
+#define FFFFFFFF 0xffffffffUL
+#endif
+
+#ifdef NO_LONG_LONG
+#undef ULLong
+#ifdef Just_16
+#undef Pack_32
+/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+ * This makes some inner loops simpler and sometimes saves work
+ * during multiplications, but it often seems to make things slightly
+ * slower. Hence the default is now to store 32 bits per Long.
+ */
+#endif
+#else /* long long available */
+#ifndef Llong
+#define Llong long long
+#endif
+#ifndef ULLong
+#define ULLong unsigned Llong
+#endif
+#endif /* NO_LONG_LONG */
+
+#ifndef MULTIPLE_THREADS
+#define ACQUIRE_DTOA_LOCK(n) /*nothing*/
+#define FREE_DTOA_LOCK(n) /*nothing*/
+#endif
+
+#define Kmax 15
+
+ struct
+Bigint {
+ struct Bigint *next;
+ int k, maxwds, sign, wds;
+ ULong x[1];
+ };
+
+ typedef struct Bigint Bigint;
+
+ static Bigint *freelist[Kmax+1];
+
+ static Bigint *
+Balloc
+#ifdef KR_headers
+ (k) int k;
+#else
+ (int k)
+#endif
+{
+ int x;
+ Bigint *rv;
+#ifndef Omit_Private_Memory
+ unsigned int len;
+#endif
+
+ ACQUIRE_DTOA_LOCK(0);
+ if ((rv = freelist[k])) {
+ freelist[k] = rv->next;
+ }
+ else {
+ x = 1 << k;
+#ifdef Omit_Private_Memory
+ rv = (Bigint *)MALLOC(sizeof(Bigint) + (x-1)*sizeof(ULong));
+#else
+ len = (sizeof(Bigint) + (x-1)*sizeof(ULong) + sizeof(double) - 1)
+ /sizeof(double);
+ if (pmem_next - private_mem + len <= (unsigned)PRIVATE_mem) {
+ rv = (Bigint*)pmem_next;
+ pmem_next += len;
+ }
+ else
+ rv = (Bigint*)MALLOC(len*sizeof(double));
+#endif
+ rv->k = k;
+ rv->maxwds = x;
+ }
+ FREE_DTOA_LOCK(0);
+ rv->sign = rv->wds = 0;
+ return rv;
+ }
+
+ static void
+Bfree
+#ifdef KR_headers
+ (v) Bigint *v;
+#else
+ (Bigint *v)
+#endif
+{
+ if (v) {
+ ACQUIRE_DTOA_LOCK(0);
+ v->next = freelist[v->k];
+ freelist[v->k] = v;
+ FREE_DTOA_LOCK(0);
+ }
+ }
+
+#define Bcopy(x,y) memcpy((char *)&x->sign, (char *)&y->sign, \
+y->wds*sizeof(Long) + 2*sizeof(int))
+
+ static Bigint *
+multadd
+#ifdef KR_headers
+ (b, m, a) Bigint *b; int m, a;
+#else
+ (Bigint *b, int m, int a) /* multiply by m and add a */
+#endif
+{
+ int i, wds;
+#ifdef ULLong
+ ULong *x;
+ ULLong carry, y;
+#else
+ ULong carry, *x, y;
+#ifdef Pack_32
+ ULong xi, z;
+#endif
+#endif
+ Bigint *b1;
+
+ wds = b->wds;
+ x = b->x;
+ i = 0;
+ carry = a;
+ do {
+#ifdef ULLong
+ y = *x * (ULLong)m + carry;
+ carry = y >> 32;
+ *x++ = (ULong)y & FFFFFFFF;
+#else
+#ifdef Pack_32
+ xi = *x;
+ y = (xi & 0xffff) * m + carry;
+ z = (xi >> 16) * m + (y >> 16);
+ carry = z >> 16;
+ *x++ = (z << 16) + (y & 0xffff);
+#else
+ y = *x * m + carry;
+ carry = y >> 16;
+ *x++ = y & 0xffff;
+#endif
+#endif
+ }
+ while(++i < wds);
+ if (carry) {
+ if (wds >= b->maxwds) {
+ b1 = Balloc(b->k+1);
+ Bcopy(b1, b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[wds++] = (ULong)carry;
+ b->wds = wds;
+ }
+ return b;
+ }
+
+ static Bigint *
+s2b
+#ifdef KR_headers
+ (s, nd0, nd, y9) CONST_ char *s; int nd0, nd; ULong y9;
+#else
+ (CONST_ char *s, int nd0, int nd, ULong y9)
+#endif
+{
+ Bigint *b;
+ int i, k;
+ Long x, y;
+
+ x = (nd + 8) / 9;
+ for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+#ifdef Pack_32
+ b = Balloc(k);
+ b->x[0] = y9;
+ b->wds = 1;
+#else
+ b = Balloc(k+1);
+ b->x[0] = y9 & 0xffff;
+ b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+ i = 9;
+ if (9 < nd0) {
+ s += 9;
+ do b = multadd(b, 10, *s++ - '0');
+ while(++i < nd0);
+ s++;
+ }
+ else
+ s += 10;
+ for(; i < nd; i++)
+ b = multadd(b, 10, *s++ - '0');
+ return b;
+ }
+
+ static int
+hi0bits
+#ifdef KR_headers
+ (x) register ULong x;
+#else
+ (register ULong x)
+#endif
+{
+ register int k = 0;
+
+ if (!(x & 0xffff0000)) {
+ k = 16;
+ x <<= 16;
+ }
+ if (!(x & 0xff000000)) {
+ k += 8;
+ x <<= 8;
+ }
+ if (!(x & 0xf0000000)) {
+ k += 4;
+ x <<= 4;
+ }
+ if (!(x & 0xc0000000)) {
+ k += 2;
+ x <<= 2;
+ }
+ if (!(x & 0x80000000)) {
+ k++;
+ if (!(x & 0x40000000))
+ return 32;
+ }
+ return k;
+ }
+
+ static int
+lo0bits
+#ifdef KR_headers
+ (y) ULong *y;
+#else
+ (ULong *y)
+#endif
+{
+ register int k;
+ register ULong x = *y;
+
+ if (x & 7) {
+ if (x & 1)
+ return 0;
+ if (x & 2) {
+ *y = x >> 1;
+ return 1;
+ }
+ *y = x >> 2;
+ return 2;
+ }
+ k = 0;
+ if (!(x & 0xffff)) {
+ k = 16;
+ x >>= 16;
+ }
+ if (!(x & 0xff)) {
+ k += 8;
+ x >>= 8;
+ }
+ if (!(x & 0xf)) {
+ k += 4;
+ x >>= 4;
+ }
+ if (!(x & 0x3)) {
+ k += 2;
+ x >>= 2;
+ }
+ if (!(x & 1)) {
+ k++;
+ x >>= 1;
+ if (!x & 1)
+ return 32;
+ }
+ *y = x;
+ return k;
+ }
+
+ static Bigint *
+i2b
+#ifdef KR_headers
+ (i) int i;
+#else
+ (int i)
+#endif
+{
+ Bigint *b;
+
+ b = Balloc(1);
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+ }
+
+ static Bigint *
+mult
+#ifdef KR_headers
+ (a, b) Bigint *a, *b;
+#else
+ (Bigint *a, Bigint *b)
+#endif
+{
+ Bigint *c;
+ int k, wa, wb, wc;
+ ULong *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+ ULong y;
+#ifdef ULLong
+ ULLong carry, z;
+#else
+ ULong carry, z;
+#ifdef Pack_32
+ ULong z2;
+#endif
+#endif
+
+ if (a->wds < b->wds) {
+ c = a;
+ a = b;
+ b = c;
+ }
+ k = a->k;
+ wa = a->wds;
+ wb = b->wds;
+ wc = wa + wb;
+ if (wc > a->maxwds)
+ k++;
+ c = Balloc(k);
+ for(x = c->x, xa = x + wc; x < xa; x++)
+ *x = 0;
+ xa = a->x;
+ xae = xa + wa;
+ xb = b->x;
+ xbe = xb + wb;
+ xc0 = c->x;
+#ifdef ULLong
+ for(; xb < xbe; xc0++) {
+ if ((y = *xb++)) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * (ULLong)y + *xc + carry;
+ carry = z >> 32;
+ *xc++ = (ULong)z & FFFFFFFF;
+ }
+ while(x < xae);
+ *xc = (ULong)carry;
+ }
+ }
+#else
+#ifdef Pack_32
+ for(; xb < xbe; xb++, xc0++) {
+ if (y = *xb & 0xffff) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = (*x & 0xffff) * y + (*xc & 0xffff) + carry;
+ carry = z >> 16;
+ z2 = (*x++ >> 16) * y + (*xc >> 16) + carry;
+ carry = z2 >> 16;
+ Storeinc(xc, z2, z);
+ }
+ while(x < xae);
+ *xc = carry;
+ }
+ if (y = *xb >> 16) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ z2 = *xc;
+ do {
+ z = (*x & 0xffff) * y + (*xc >> 16) + carry;
+ carry = z >> 16;
+ Storeinc(xc, z, z2);
+ z2 = (*x++ >> 16) * y + (*xc & 0xffff) + carry;
+ carry = z2 >> 16;
+ }
+ while(x < xae);
+ *xc = z2;
+ }
+ }
+#else
+ for(; xb < xbe; xc0++) {
+ if (y = *xb++) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * y + *xc + carry;
+ carry = z >> 16;
+ *xc++ = z & 0xffff;
+ }
+ while(x < xae);
+ *xc = carry;
+ }
+ }
+#endif
+#endif
+ for(xc0 = c->x, xc = xc0 + wc; wc > 0 && !*--xc; --wc) ;
+ c->wds = wc;
+ return c;
+ }
+
+ static Bigint *p5s;
+
+ static Bigint *
+pow5mult
+#ifdef KR_headers
+ (b, k) Bigint *b; int k;
+#else
+ (Bigint *b, int k)
+#endif
+{
+ Bigint *b1, *p5, *p51;
+ int i;
+ static int p05[3] = { 5, 25, 125 };
+
+ if ((i = k & 3))
+ b = multadd(b, p05[i-1], 0);
+
+ if (!(k >>= 2))
+ return b;
+ if (!(p5 = p5s)) {
+ /* first time */
+#ifdef MULTIPLE_THREADS
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p5 = p5s)) {
+ p5 = p5s = i2b(625);
+ p5->next = 0;
+ }
+ FREE_DTOA_LOCK(1);
+#else
+ p5 = p5s = i2b(625);
+ p5->next = 0;
+#endif
+ }
+ for(;;) {
+ if (k & 1) {
+ b1 = mult(b, p5);
+ Bfree(b);
+ b = b1;
+ }
+ if (!(k >>= 1))
+ break;
+ if (!(p51 = p5->next)) {
+#ifdef MULTIPLE_THREADS
+ ACQUIRE_DTOA_LOCK(1);
+ if (!(p51 = p5->next)) {
+ p51 = p5->next = mult(p5,p5);
+ p51->next = 0;
+ }
+ FREE_DTOA_LOCK(1);
+#else
+ p51 = p5->next = mult(p5,p5);
+ p51->next = 0;
+#endif
+ }
+ p5 = p51;
+ }
+ return b;
+ }
+
+ static Bigint *
+lshift
+#ifdef KR_headers
+ (b, k) Bigint *b; int k;
+#else
+ (Bigint *b, int k)
+#endif
+{
+ int i, k1, n, n1;
+ Bigint *b1;
+ ULong *x, *x1, *xe, z;
+
+#ifdef Pack_32
+ n = k >> 5;
+#else
+ n = k >> 4;
+#endif
+ k1 = b->k;
+ n1 = n + b->wds + 1;
+ for(i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ b1 = Balloc(k1);
+ x1 = b1->x;
+ for(i = 0; i < n; i++)
+ *x1++ = 0;
+ x = b->x;
+ xe = x + b->wds;
+#ifdef Pack_32
+ if (k &= 0x1f) {
+ k1 = 32 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k | z;
+ z = *x++ >> k1;
+ }
+ while(x < xe);
+ if ((*x1 = z))
+ ++n1;
+ }
+#else
+ if (k &= 0xf) {
+ k1 = 16 - k;
+ z = 0;
+ do {
+ *x1++ = *x << k & 0xffff | z;
+ z = *x++ >> k1;
+ }
+ while(x < xe);
+ if (*x1 = z)
+ ++n1;
+ }
+#endif
+ else do
+ *x1++ = *x++;
+ while(x < xe);
+ b1->wds = n1 - 1;
+ Bfree(b);
+ return b1;
+ }
+
+ static int
+cmp
+#ifdef KR_headers
+ (a, b) Bigint *a, *b;
+#else
+ (Bigint *a, Bigint *b)
+#endif
+{
+ ULong *xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a->wds;
+ j = b->wds;
+#ifdef DEBUG
+ if (i > 1 && !a->x[i-1])
+ Bug("cmp called with a->x[a->wds-1] == 0");
+ if (j > 1 && !b->x[j-1])
+ Bug("cmp called with b->x[b->wds-1] == 0");
+#endif
+ if (i -= j)
+ return i;
+ xa0 = a->x;
+ xa = xa0 + j;
+ xb0 = b->x;
+ xb = xb0 + j;
+ for(;;) {
+ if (*--xa != *--xb)
+ return *xa < *xb ? -1 : 1;
+ if (xa <= xa0)
+ break;
+ }
+ return 0;
+ }
+
+ static Bigint *
+diff
+#ifdef KR_headers
+ (a, b) Bigint *a, *b;
+#else
+ (Bigint *a, Bigint *b)
+#endif
+{
+ Bigint *c;
+ int i, wa, wb;
+ ULong *xa, *xae, *xb, *xbe, *xc;
+#ifdef ULLong
+ ULLong borrow, y;
+#else
+ ULong borrow, y;
+#ifdef Pack_32
+ ULong z;
+#endif
+#endif
+
+ i = cmp(a,b);
+ if (!i) {
+ c = Balloc(0);
+ c->wds = 1;
+ c->x[0] = 0;
+ return c;
+ }
+ if (i < 0) {
+ c = a;
+ a = b;
+ b = c;
+ i = 1;
+ }
+ else
+ i = 0;
+ c = Balloc(a->k);
+ c->sign = i;
+ wa = a->wds;
+ xa = a->x;
+ xae = xa + wa;
+ wb = b->wds;
+ xb = b->x;
+ xbe = xb + wb;
+ xc = c->x;
+ borrow = 0;
+#ifdef ULLong
+ do {
+ y = (ULLong)*xa++ - *xb++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = (ULong)y & FFFFFFFF;
+ }
+ while(xb < xbe);
+ while(xa < xae) {
+ y = *xa++ - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *xc++ = (ULong)y & FFFFFFFF;
+ }
+#else
+#ifdef Pack_32
+ do {
+ y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+ while(xb < xbe);
+ while(xa < xae) {
+ y = (*xa & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*xa++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+#else
+ do {
+ y = *xa++ - *xb++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ }
+ while(xb < xbe);
+ while(xa < xae) {
+ y = *xa++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ }
+#endif
+#endif
+ while(!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+ }
+
+ static double
+ulp
+#ifdef KR_headers
+ (x) double x;
+#else
+ (double x)
+#endif
+{
+ register Long L;
+ double a;
+
+ L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+ if (L > 0) {
+#endif
+#endif
+#ifdef IBM
+ L |= Exp_msk1 >> 4;
+#endif
+ word0(a) = L;
+ word1(a) = 0;
+#ifndef Avoid_Underflow
+#ifndef Sudden_Underflow
+ }
+ else {
+ L = -L >> Exp_shift;
+ if (L < Exp_shift) {
+ word0(a) = 0x80000 >> L;
+ word1(a) = 0;
+ }
+ else {
+ word0(a) = 0;
+ L -= Exp_shift;
+ word1(a) = L >= 31 ? 1 : 1 << 31 - L;
+ }
+ }
+#endif
+#endif
+ return dval(a);
+ }
+
+ static double
+b2d
+#ifdef KR_headers
+ (a, e) Bigint *a; int *e;
+#else
+ (Bigint *a, int *e)
+#endif
+{
+ ULong *xa, *xa0, w, y, z;
+ int k;
+ double d;
+#ifdef VAX
+ ULong d0, d1;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+#ifdef DEBUG
+ if (!y) Bug("zero y in b2d");
+#endif
+ k = hi0bits(y);
+ *e = 32 - k;
+#ifdef Pack_32
+ if (k < Ebits) {
+ d0 = Exp_1 | y >> Ebits - k;
+ w = xa > xa0 ? *--xa : 0;
+ d1 = y << (32-Ebits) + k | w >> Ebits - k;
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ if (k -= Ebits) {
+ d0 = Exp_1 | y << k | z >> 32 - k;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k | y >> 32 - k;
+ }
+ else {
+ d0 = Exp_1 | y;
+ d1 = z;
+ }
+#else
+ if (k < Ebits + 16) {
+ z = xa > xa0 ? *--xa : 0;
+ d0 = Exp_1 | y << k - Ebits | z >> Ebits + 16 - k;
+ w = xa > xa0 ? *--xa : 0;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = z << k + 16 - Ebits | w << k - Ebits | y >> 16 + Ebits - k;
+ goto ret_d;
+ }
+ z = xa > xa0 ? *--xa : 0;
+ w = xa > xa0 ? *--xa : 0;
+ k -= Ebits + 16;
+ d0 = Exp_1 | y << k + 16 | z << k | w >> 16 - k;
+ y = xa > xa0 ? *--xa : 0;
+ d1 = w << k + 16 | y << k;
+#endif
+ ret_d:
+#ifdef VAX
+ word0(d) = d0 >> 16 | d0 << 16;
+ word1(d) = d1 >> 16 | d1 << 16;
+#else
+#undef d0
+#undef d1
+#endif
+ return dval(d);
+ }
+
+ static Bigint *
+d2b
+#ifdef KR_headers
+ (d, e, bits) double d; int *e, *bits;
+#else
+ (double d, int *e, int *bits)
+#endif
+{
+ Bigint *b;
+ int de, k;
+ ULong *x, y, z;
+#ifndef Sudden_Underflow
+ int i;
+#endif
+#ifdef VAX
+ ULong d0, d1;
+ d0 = word0(d) >> 16 | word0(d) << 16;
+ d1 = word1(d) >> 16 | word1(d) << 16;
+#else
+#define d0 word0(d)
+#define d1 word1(d)
+#endif
+
+#ifdef Pack_32
+ b = Balloc(1);
+#else
+ b = Balloc(2);
+#endif
+ x = b->x;
+
+ z = d0 & Frac_mask;
+ d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+#ifdef Sudden_Underflow
+ de = (int)(d0 >> Exp_shift);
+#ifndef IBM
+ z |= Exp_msk11;
+#endif
+#else
+ if ((de = (int)(d0 >> Exp_shift)))
+ z |= Exp_msk1;
+#endif
+#ifdef Pack_32
+ if ((y = d1)) {
+ if ((k = lo0bits(&y))) {
+ x[0] = y | z << 32 - k;
+ z >>= k;
+ }
+ else
+ x[0] = y;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = (x[1] = z) ? 2 : 1;
+ }
+ else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ x[0] = z;
+#ifndef Sudden_Underflow
+ i =
+#endif
+ b->wds = 1;
+ k += 32;
+ }
+#else
+ if (y = d1) {
+ if (k = lo0bits(&y))
+ if (k >= 16) {
+ x[0] = y | z << 32 - k & 0xffff;
+ x[1] = z >> k - 16 & 0xffff;
+ x[2] = z >> k;
+ i = 2;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16 | z << 16 - k & 0xffff;
+ x[2] = z >> k & 0xffff;
+ x[3] = z >> k+16;
+ i = 3;
+ }
+ else {
+ x[0] = y & 0xffff;
+ x[1] = y >> 16;
+ x[2] = z & 0xffff;
+ x[3] = z >> 16;
+ i = 3;
+ }
+ }
+ else {
+#ifdef DEBUG
+ if (!z)
+ Bug("Zero passed to d2b");
+#endif
+ k = lo0bits(&z);
+ if (k >= 16) {
+ x[0] = z;
+ i = 0;
+ }
+ else {
+ x[0] = z & 0xffff;
+ x[1] = z >> 16;
+ i = 1;
+ }
+ k += 32;
+ }
+ while(!x[i])
+ --i;
+ b->wds = i + 1;
+#endif
+#ifndef Sudden_Underflow
+ if (de) {
+#endif
+#ifdef IBM
+ *e = (de - Bias - (P-1) << 2) + k;
+ *bits = 4*P + 8 - k - hi0bits(word0(d) & Frac_mask);
+#else
+ *e = de - Bias - (P-1) + k;
+ *bits = P - k;
+#endif
+#ifndef Sudden_Underflow
+ }
+ else {
+ *e = de - Bias - (P-1) + 1 + k;
+#ifdef Pack_32
+ *bits = 32*i - hi0bits(x[i-1]);
+#else
+ *bits = (i+2)*16 - hi0bits(x[i]);
+#endif
+ }
+#endif
+ return b;
+ }
+#undef d0
+#undef d1
+
+ static double
+ratio
+#ifdef KR_headers
+ (a, b) Bigint *a, *b;
+#else
+ (Bigint *a, Bigint *b)
+#endif
+{
+ double da, db;
+ int k, ka, kb;
+
+ dval(da) = b2d(a, &ka);
+ dval(db) = b2d(b, &kb);
+#ifdef Pack_32
+ k = ka - kb + 32*(a->wds - b->wds);
+#else
+ k = ka - kb + 16*(a->wds - b->wds);
+#endif
+#ifdef IBM
+ if (k > 0) {
+ word0(da) += (k >> 2)*Exp_msk1;
+ if (k &= 3)
+ dval(da) *= 1 << k;
+ }
+ else {
+ k = -k;
+ word0(db) += (k >> 2)*Exp_msk1;
+ if (k &= 3)
+ dval(db) *= 1 << k;
+ }
+#else
+ if (k > 0)
+ word0(da) += k*Exp_msk1;
+ else {
+ k = -k;
+ word0(db) += k*Exp_msk1;
+ }
+#endif
+ return dval(da) / dval(db);
+ }
+
+ static CONST_ double
+tens[] = {
+ 1e0, 1e1, 1e2, 1e3, 1e4, 1e5, 1e6, 1e7, 1e8, 1e9,
+ 1e10, 1e11, 1e12, 1e13, 1e14, 1e15, 1e16, 1e17, 1e18, 1e19,
+ 1e20, 1e21, 1e22
+#ifdef VAX
+ , 1e23, 1e24
+#endif
+ };
+
+ static CONST_ double
+#ifdef IEEE_Arith
+bigtens[] = { 1e16, 1e32, 1e64, 1e128, 1e256 };
+static CONST_ double tinytens[] = { 1e-16, 1e-32, 1e-64, 1e-128,
+#ifdef Avoid_Underflow
+ 9007199254740992.*9007199254740992.e-256
+ /* = 2^106 * 1e-53 */
+#else
+ 1e-256
+#endif
+ };
+/* The factor of 2^53 in tinytens[4] helps us avoid setting the underflow */
+/* flag unnecessarily. It leads to a song and dance at the end of strtod. */
+#define Scale_Bit 0x10
+#define n_bigtens 5
+#else
+#ifdef IBM
+bigtens[] = { 1e16, 1e32, 1e64 };
+static CONST_ double tinytens[] = { 1e-16, 1e-32, 1e-64 };
+#define n_bigtens 3
+#else
+bigtens[] = { 1e16, 1e32 };
+static CONST_ double tinytens[] = { 1e-16, 1e-32 };
+#define n_bigtens 2
+#endif
+#endif
+
+#ifndef IEEE_Arith
+#undef INFNAN_CHECK
+#endif
+
+#ifdef INFNAN_CHECK
+
+#ifndef NAN_WORD0
+#define NAN_WORD0 0x7ff80000
+#endif
+
+#ifndef NAN_WORD1
+#define NAN_WORD1 0
+#endif
+
+ static int
+match
+#ifdef KR_headers
+ (sp, t) char **sp, *t;
+#else
+ (CONST_ char **sp, CONST_ char *t)
+#endif
+{
+ int c, d;
+ CONST_ char *s = *sp;
+
+ while((d = *t++)) {
+ if ((c = *++s) >= 'A' && c <= 'Z')
+ c += 'a' - 'A';
+ if (c != d)
+ return 0;
+ }
+ *sp = s + 1;
+ return 1;
+ }
+
+#ifndef No_Hex_NaN
+ static void
+hexnan
+#ifdef KR_headers
+ (rvp, sp) double *rvp; CONST_ char **sp;
+#else
+ (double *rvp, CONST_ char **sp)
+#endif
+{
+ ULong c, x[2];
+ CONST_ char *s;
+ int havedig, udx0, xshift;
+
+ x[0] = x[1] = 0;
+ havedig = xshift = 0;
+ udx0 = 1;
+ s = *sp;
+ while((c = *(CONST_ unsigned char*)++s)) {
+ if (c >= '0' && c <= '9')
+ c -= '0';
+ else if (c >= 'a' && c <= 'f')
+ c += 10 - 'a';
+ else if (c >= 'A' && c <= 'F')
+ c += 10 - 'A';
+ else if (c <= ' ') {
+ if (udx0 && havedig) {
+ udx0 = 0;
+ xshift = 1;
+ }
+ continue;
+ }
+ else if (/*(*/ c == ')' && havedig) {
+ *sp = s + 1;
+ break;
+ }
+ else
+ return; /* invalid form: don't change *sp */
+ havedig = 1;
+ if (xshift) {
+ xshift = 0;
+ x[0] = x[1];
+ x[1] = 0;
+ }
+ if (udx0)
+ x[0] = (x[0] << 4) | (x[1] >> 28);
+ x[1] = (x[1] << 4) | c;
+ }
+ if ((x[0] &= 0xfffff) || x[1]) {
+ word0(*rvp) = Exp_mask | x[0];
+ word1(*rvp) = x[1];
+ }
+ }
+#endif /*No_Hex_NaN*/
+#endif /* INFNAN_CHECK */
+
+ double
+strtod
+#ifdef KR_headers
+ (s00, se) CONST_ char *s00; char **se;
+#else
+ (CONST_ char *s00, char **se)
+#endif
+{
+#ifdef Avoid_Underflow
+ int scale;
+#endif
+ int bb2, bb5, bbe, bd2, bd5, bbbits, bs2, c, dsign,
+ e, e1, esign, i, j, k, nd, nd0, nf, nz, nz0, sign;
+ CONST_ char *s, *s0, *s1;
+ double aadj, aadj1, adj, rv, rv0;
+ Long L;
+ ULong y, z;
+ Bigint *bb = NULL, *bb1 = NULL, *bd = NULL, *bd0 = NULL, *bs = NULL, *delta = NULL;
+#ifdef SET_INEXACT
+ int inexact, oldinexact;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ int rounding;
+#endif
+
+ sign = nz0 = nz = 0;
+ dval(rv) = 0.;
+ for(s = s00;;s++) switch(*s) {
+ case '-':
+ sign = 1;
+ /* no break */
+ case '+':
+ if (*++s)
+ goto break2;
+ /* no break */
+ case 0:
+ goto ret0;
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ continue;
+ default:
+ goto break2;
+ }
+ break2:
+ if (*s == '0') {
+ nz0 = 1;
+ while(*++s == '0') ;
+ if (!*s)
+ goto ret;
+ }
+ s0 = s;
+ y = z = 0;
+ for(nd = nf = 0; (c = *s) >= '0' && c <= '9'; nd++, s++)
+ if (nd < 9)
+ y = 10*y + c - '0';
+ else if (nd < 16)
+ z = 10*z + c - '0';
+ nd0 = nd;
+ if (c == '.') {
+ c = *++s;
+ if (!nd) {
+ for(; c == '0'; c = *++s)
+ nz++;
+ if (c > '0' && c <= '9') {
+ s0 = s;
+ nf += nz;
+ nz = 0;
+ goto have_dig;
+ }
+ goto dig_done;
+ }
+ for(; c >= '0' && c <= '9'; c = *++s) {
+ have_dig:
+ nz++;
+ if (c -= '0') {
+ nf += nz;
+ for(i = 1; i < nz; i++)
+ if (nd++ < 9)
+ y *= 10;
+ else if (nd <= DBL_DIG + 1)
+ z *= 10;
+ if (nd++ < 9)
+ y = 10*y + c;
+ else if (nd <= DBL_DIG + 1)
+ z = 10*z + c;
+ nz = 0;
+ }
+ }
+ }
+ dig_done:
+ e = 0;
+ if (c == 'e' || c == 'E') {
+ if (!nd && !nz && !nz0) {
+ goto ret0;
+ }
+ s00 = s;
+ esign = 0;
+ switch(c = *++s) {
+ case '-':
+ esign = 1;
+ case '+':
+ c = *++s;
+ }
+ if (c >= '0' && c <= '9') {
+ while(c == '0')
+ c = *++s;
+ if (c > '0' && c <= '9') {
+ L = c - '0';
+ s1 = s;
+ while((c = *++s) >= '0' && c <= '9')
+ L = 10*L + c - '0';
+ if (s - s1 > 8 || L > 19999)
+ /* Avoid confusion from exponents
+ * so large that e might overflow.
+ */
+ e = 19999; /* safe for 16 bit ints */
+ else
+ e = (int)L;
+ if (esign)
+ e = -e;
+ }
+ else
+ e = 0;
+ }
+ else
+ s = s00;
+ }
+ if (!nd) {
+ if (!nz && !nz0) {
+#ifdef INFNAN_CHECK
+ /* Check for Nan and Infinity */
+ switch(c) {
+ case 'i':
+ case 'I':
+ if (match(&s,"nf")) {
+ --s;
+ if (!match(&s,"inity"))
+ ++s;
+ word0(rv) = 0x7ff00000;
+ word1(rv) = 0;
+ goto ret;
+ }
+ break;
+ case 'n':
+ case 'N':
+ if (match(&s, "an")) {
+ word0(rv) = NAN_WORD0;
+ word1(rv) = NAN_WORD1;
+#ifndef No_Hex_NaN
+ if (*s == '(') /*)*/
+ hexnan(&rv, &s);
+#endif
+ goto ret;
+ }
+ }
+#endif /* INFNAN_CHECK */
+ ret0:
+ s = s00;
+ sign = 0;
+ }
+ goto ret;
+ }
+ e1 = e -= nf;
+
+ /* Now we have nd0 digits, starting at s0, followed by a
+ * decimal point, followed by nd-nd0 digits. The number we're
+ * after is the integer represented by those digits times
+ * 10**e */
+
+ if (!nd0)
+ nd0 = nd;
+ k = nd < DBL_DIG + 1 ? nd : DBL_DIG + 1;
+ dval(rv) = y;
+ if (k > 9) {
+#ifdef SET_INEXACT
+ if (k > DBL_DIG)
+ oldinexact = get_inexact();
+#endif
+ dval(rv) = tens[k - 9] * dval(rv) + z;
+ }
+ bd0 = 0;
+ if (nd <= DBL_DIG
+#ifndef RND_PRODQUOT
+#ifndef Honor_FLT_ROUNDS
+ && Flt_Rounds == 1
+#endif
+#endif
+ ) {
+ if (!e)
+ goto ret;
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+#ifdef VAX
+ goto vax_ovfl_check;
+#else
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ rv = -rv;
+ sign = 0;
+ }
+#endif
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+ goto ret;
+#endif
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ rv = -rv;
+ sign = 0;
+ }
+#endif
+ e -= i;
+ dval(rv) *= tens[i];
+#ifdef VAX
+ /* VAX exponent range is so narrow we must
+ * worry about overflow here...
+ */
+ vax_ovfl_check:
+ word0(rv) -= P*Exp_msk1;
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+ if ((word0(rv) & Exp_mask)
+ > Exp_msk1*(DBL_MAX_EXP+Bias-1-P))
+ goto ovfl;
+ word0(rv) += P*Exp_msk1;
+#else
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+#endif
+ goto ret;
+ }
+ }
+#ifndef Inaccurate_Divide
+ else if (e >= -Ten_pmax) {
+#ifdef Honor_FLT_ROUNDS
+ /* round correctly FLT_ROUNDS = 2 or 3 */
+ if (sign) {
+ rv = -rv;
+ sign = 0;
+ }
+#endif
+ /* rv = */ rounded_quotient(dval(rv), tens[-e]);
+ goto ret;
+ }
+#endif
+ }
+ e1 += nd - k;
+
+#ifdef IEEE_Arith
+#ifdef SET_INEXACT
+ inexact = 1;
+ if (k <= DBL_DIG)
+ oldinexact = get_inexact();
+#endif
+#ifdef Avoid_Underflow
+ scale = 0;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ if ((rounding = Flt_Rounds) >= 2) {
+ if (sign)
+ rounding = rounding == 2 ? 0 : 2;
+ else
+ if (rounding != 2)
+ rounding = 0;
+ }
+#endif
+#endif /*IEEE_Arith*/
+
+ /* Get starting approximation = rv * 10**e1 */
+
+ if (e1 > 0) {
+ if ((i = e1 & 15))
+ dval(rv) *= tens[i];
+ if (e1 &= ~15) {
+ if (e1 > DBL_MAX_10_EXP) {
+ ovfl:
+#ifndef NO_ERRNO
+ errno = ERANGE;
+#endif
+ /* Can't trust HUGE_VAL */
+#ifdef IEEE_Arith
+#ifdef Honor_FLT_ROUNDS
+ switch(rounding) {
+ case 0: /* toward 0 */
+ case 3: /* toward -infinity */
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ break;
+ default:
+ word0(rv) = Exp_mask;
+ word1(rv) = 0;
+ }
+#else /*Honor_FLT_ROUNDS*/
+ word0(rv) = Exp_mask;
+ word1(rv) = 0;
+#endif /*Honor_FLT_ROUNDS*/
+#ifdef SET_INEXACT
+ /* set overflow bit */
+ dval(rv0) = 1e300;
+ dval(rv0) *= dval(rv0);
+#endif
+#else /*IEEE_Arith*/
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+#endif /*IEEE_Arith*/
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+ e1 >>= 4;
+ for(j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(rv) *= bigtens[j];
+ /* The last multiplication could overflow. */
+ word0(rv) -= P*Exp_msk1;
+ dval(rv) *= bigtens[j];
+ if ((z = word0(rv) & Exp_mask)
+ > Exp_msk1*(DBL_MAX_EXP+Bias-P))
+ goto ovfl;
+ if (z > Exp_msk1*(DBL_MAX_EXP+Bias-1-P)) {
+ /* set to largest number */
+ /* (Can't trust DBL_MAX) */
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ }
+ else
+ word0(rv) += P*Exp_msk1;
+ }
+ }
+ else if (e1 < 0) {
+ e1 = -e1;
+ if ((i = e1 & 15))
+ dval(rv) /= tens[i];
+ if (e1 >>= 4) {
+ if (e1 >= 1 << n_bigtens)
+ goto undfl;
+#ifdef Avoid_Underflow
+ if (e1 & Scale_Bit)
+ scale = 2*P;
+ for(j = 0; e1 > 0; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(rv) *= tinytens[j];
+ if (scale && (j = 2*P + 1 - ((word0(rv) & Exp_mask)
+ >> Exp_shift)) > 0) {
+ /* scaled rv is denormal; zap j low bits */
+ if (j >= 32) {
+ word1(rv) = 0;
+ if (j >= 53)
+ word0(rv) = (P+2)*Exp_msk1;
+ else
+ word0(rv) &= 0xffffffff << j-32;
+ }
+ else
+ word1(rv) &= 0xffffffff << j;
+ }
+#else
+ for(j = 0; e1 > 1; j++, e1 >>= 1)
+ if (e1 & 1)
+ dval(rv) *= tinytens[j];
+ /* The last multiplication could underflow. */
+ dval(rv0) = dval(rv);
+ dval(rv) *= tinytens[j];
+ if (!dval(rv)) {
+ dval(rv) = 2.*dval(rv0);
+ dval(rv) *= tinytens[j];
+#endif
+ if (!dval(rv)) {
+ undfl:
+ dval(rv) = 0.;
+#ifndef NO_ERRNO
+ errno = ERANGE;
+#endif
+ if (bd0)
+ goto retfree;
+ goto ret;
+ }
+#ifndef Avoid_Underflow
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ /* The refinement below will clean
+ * this approximation up.
+ */
+ }
+#endif
+ }
+ }
+
+ /* Now the hard part -- adjusting rv to the correct value.*/
+
+ /* Put digits into bd: true value = bd * 10^e */
+
+ bd0 = s2b(s0, nd0, nd, y);
+
+ for(;;) {
+ bd = Balloc(bd0->k);
+ Bcopy(bd, bd0);
+ bb = d2b(dval(rv), &bbe, &bbbits); /* rv = bb * 2^bbe */
+ bs = i2b(1);
+
+ if (e >= 0) {
+ bb2 = bb5 = 0;
+ bd2 = bd5 = e;
+ }
+ else {
+ bb2 = bb5 = -e;
+ bd2 = bd5 = 0;
+ }
+ if (bbe >= 0)
+ bb2 += bbe;
+ else
+ bd2 -= bbe;
+ bs2 = bb2;
+#ifdef Honor_FLT_ROUNDS
+ if (rounding != 1)
+ bs2++;
+#endif
+#ifdef Avoid_Underflow
+ j = bbe - scale;
+ i = j + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j += P - Emin;
+ else
+ j = P + 1 - bbbits;
+#else /*Avoid_Underflow*/
+#ifdef Sudden_Underflow
+#ifdef IBM
+ j = 1 + 4*P - 3 - bbbits + ((bbe + bbbits - 1) & 3);
+#else
+ j = P + 1 - bbbits;
+#endif
+#else /*Sudden_Underflow*/
+ j = bbe;
+ i = j + bbbits - 1; /* logb(rv) */
+ if (i < Emin) /* denormal */
+ j += P - Emin;
+ else
+ j = P + 1 - bbbits;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ bb2 += j;
+ bd2 += j;
+#ifdef Avoid_Underflow
+ bd2 += scale;
+#endif
+ i = bb2 < bd2 ? bb2 : bd2;
+ if (i > bs2)
+ i = bs2;
+ if (i > 0) {
+ bb2 -= i;
+ bd2 -= i;
+ bs2 -= i;
+ }
+ if (bb5 > 0) {
+ bs = pow5mult(bs, bb5);
+ bb1 = mult(bs, bb);
+ Bfree(bb);
+ bb = bb1;
+ }
+ if (bb2 > 0)
+ bb = lshift(bb, bb2);
+ if (bd5 > 0)
+ bd = pow5mult(bd, bd5);
+ if (bd2 > 0)
+ bd = lshift(bd, bd2);
+ if (bs2 > 0)
+ bs = lshift(bs, bs2);
+ delta = diff(bb, bd);
+ dsign = delta->sign;
+ delta->sign = 0;
+ i = cmp(delta, bs);
+#ifdef Honor_FLT_ROUNDS
+ if (rounding != 1) {
+ if (i < 0) {
+ /* Error is less than an ulp */
+ if (!delta->x[0] && delta->wds <= 1) {
+ /* exact */
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ if (rounding) {
+ if (dsign) {
+ adj = 1.;
+ goto apply_adj;
+ }
+ }
+ else if (!dsign) {
+ adj = -1.;
+ if (!word1(rv)
+ && !(word0(rv) & Frac_mask)) {
+ y = word0(rv) & Exp_mask;
+#ifdef Avoid_Underflow
+ if (!scale || y > 2*P*Exp_msk1)
+#else
+ if (y)
+#endif
+ {
+ delta = lshift(delta,Log2P);
+ if (cmp(delta, bs) <= 0)
+ adj = -0.5;
+ }
+ }
+ apply_adj:
+#ifdef Avoid_Underflow
+ if (scale && (y = word0(rv) & Exp_mask)
+ <= 2*P*Exp_msk1)
+ word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <=
+ P*Exp_msk1) {
+ word0(rv) += P*Exp_msk1;
+ dval(rv) += adj*ulp(dval(rv));
+ word0(rv) -= P*Exp_msk1;
+ }
+ else
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ dval(rv) += adj*ulp(dval(rv));
+ }
+ break;
+ }
+ adj = ratio(delta, bs);
+ if (adj < 1.)
+ adj = 1.;
+ if (adj <= 0x7ffffffe) {
+ /* adj = rounding ? ceil(adj) : floor(adj); */
+ y = adj;
+ if (y != adj) {
+ if (!((rounding>>1) ^ dsign))
+ y++;
+ adj = y;
+ }
+ }
+#ifdef Avoid_Underflow
+ if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+ word0(adj) += (2*P+1)*Exp_msk1 - y;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+ word0(rv) += P*Exp_msk1;
+ adj *= ulp(dval(rv));
+ if (dsign)
+ dval(rv) += adj;
+ else
+ dval(rv) -= adj;
+ word0(rv) -= P*Exp_msk1;
+ goto cont;
+ }
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ adj *= ulp(dval(rv));
+ if (dsign)
+ dval(rv) += adj;
+ else
+ dval(rv) -= adj;
+ goto cont;
+ }
+#endif /*Honor_FLT_ROUNDS*/
+
+ if (i < 0) {
+ /* Error is less than half an ulp -- check for
+ * special case of mantissa a power of two.
+ */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask
+#ifdef IEEE_Arith
+#ifdef Avoid_Underflow
+ || (word0(rv) & Exp_mask) <= (2*P+1)*Exp_msk1
+#else
+ || (word0(rv) & Exp_mask) <= Exp_msk1
+#endif
+#endif
+ ) {
+#ifdef SET_INEXACT
+ if (!delta->x[0] && delta->wds <= 1)
+ inexact = 0;
+#endif
+ break;
+ }
+ if (!delta->x[0] && delta->wds <= 1) {
+ /* exact result */
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ delta = lshift(delta,Log2P);
+ if (cmp(delta, bs) > 0)
+ goto drop_down;
+ break;
+ }
+ if (i == 0) {
+ /* exactly half-way between */
+ if (dsign) {
+ if ((word0(rv) & Bndry_mask1) == Bndry_mask1
+ && word1(rv) == (
+#ifdef Avoid_Underflow
+ (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
+ ? (0xffffffff & (0xffffffff << (2*P+1-(y>>Exp_shift)))) :
+#endif
+ 0xffffffff)) {
+ /*boundary case -- increment exponent*/
+ word0(rv) = (word0(rv) & Exp_mask)
+ + Exp_msk1
+#ifdef IBM
+ | Exp_msk1 >> 4
+#endif
+ ;
+ word1(rv) = 0;
+#ifdef Avoid_Underflow
+ dsign = 0;
+#endif
+ break;
+ }
+ }
+ else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
+ drop_down:
+ /* boundary case -- decrement exponent */
+#ifdef Sudden_Underflow /*{{*/
+ L = word0(rv) & Exp_mask;
+#ifdef IBM
+ if (L < Exp_msk1)
+#else
+#ifdef Avoid_Underflow
+ if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
+#else
+ if (L <= Exp_msk1)
+#endif /*Avoid_Underflow*/
+#endif /*IBM*/
+ goto undfl;
+ L -= Exp_msk1;
+#else /*Sudden_Underflow}{*/
+#ifdef Avoid_Underflow
+ if (scale) {
+ L = word0(rv) & Exp_mask;
+ if (L <= (2*P+1)*Exp_msk1) {
+ if (L > (P+2)*Exp_msk1)
+ /* round even ==> */
+ /* accept rv */
+ break;
+ /* rv = smallest denormal */
+ goto undfl;
+ }
+ }
+#endif /*Avoid_Underflow*/
+ L = (word0(rv) & Exp_mask) - Exp_msk1;
+#endif /*Sudden_Underflow}}*/
+ word0(rv) = L | Bndry_mask1;
+ word1(rv) = 0xffffffff;
+#ifdef IBM
+ goto cont;
+#else
+ break;
+#endif
+ }
+#ifndef ROUND_BIASED
+ if (!(word1(rv) & LSB))
+ break;
+#endif
+ if (dsign)
+ dval(rv) += ulp(dval(rv));
+#ifndef ROUND_BIASED
+ else {
+ dval(rv) -= ulp(dval(rv));
+#ifndef Sudden_Underflow
+ if (!dval(rv))
+ goto undfl;
+#endif
+ }
+#ifdef Avoid_Underflow
+ dsign = 1 - dsign;
+#endif
+#endif
+ break;
+ }
+ if ((aadj = ratio(delta, bs)) <= 2.) {
+ if (dsign)
+ aadj = aadj1 = 1.;
+ else if (word1(rv) || word0(rv) & Bndry_mask) {
+#ifndef Sudden_Underflow
+ if (word1(rv) == Tiny1 && !word0(rv))
+ goto undfl;
+#endif
+ aadj = 1.;
+ aadj1 = -1.;
+ }
+ else {
+ /* special case -- power of FLT_RADIX to be */
+ /* rounded down... */
+
+ if (aadj < 2./FLT_RADIX)
+ aadj = 1./FLT_RADIX;
+ else
+ aadj *= 0.5;
+ aadj1 = -aadj;
+ }
+ }
+ else {
+ aadj *= 0.5;
+ aadj1 = dsign ? aadj : -aadj;
+#ifdef Check_FLT_ROUNDS
+ switch(Rounding) {
+ case 2: /* towards +infinity */
+ aadj1 -= 0.5;
+ break;
+ case 0: /* towards 0 */
+ case 3: /* towards -infinity */
+ aadj1 += 0.5;
+ }
+#else
+ if (Flt_Rounds == 0)
+ aadj1 += 0.5;
+#endif /*Check_FLT_ROUNDS*/
+ }
+ y = word0(rv) & Exp_mask;
+
+ /* Check for overflow */
+
+ if (y == Exp_msk1*(DBL_MAX_EXP+Bias-1)) {
+ dval(rv0) = dval(rv);
+ word0(rv) -= P*Exp_msk1;
+ adj = aadj1 * ulp(dval(rv));
+ dval(rv) += adj;
+ if ((word0(rv) & Exp_mask) >=
+ Exp_msk1*(DBL_MAX_EXP+Bias-P)) {
+ if (word0(rv0) == Big0 && word1(rv0) == Big1)
+ goto ovfl;
+ word0(rv) = Big0;
+ word1(rv) = Big1;
+ goto cont;
+ }
+ else
+ word0(rv) += P*Exp_msk1;
+ }
+ else {
+#ifdef Avoid_Underflow
+ if (scale && y <= 2*P*Exp_msk1) {
+ if (aadj <= 0x7fffffff) {
+ if ((z = (ULong)aadj) <= 0)
+ z = 1;
+ aadj = z;
+ aadj1 = dsign ? aadj : -aadj;
+ }
+ word0(aadj1) += (2*P+1)*Exp_msk1 - y;
+ }
+ adj = aadj1 * ulp(dval(rv));
+ dval(rv) += adj;
+#else
+#ifdef Sudden_Underflow
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1) {
+ dval(rv0) = dval(rv);
+ word0(rv) += P*Exp_msk1;
+ adj = aadj1 * ulp(dval(rv));
+ dval(rv) += adj;
+#ifdef IBM
+ if ((word0(rv) & Exp_mask) < P*Exp_msk1)
+#else
+ if ((word0(rv) & Exp_mask) <= P*Exp_msk1)
+#endif
+ {
+ if (word0(rv0) == Tiny0
+ && word1(rv0) == Tiny1)
+ goto undfl;
+ word0(rv) = Tiny0;
+ word1(rv) = Tiny1;
+ goto cont;
+ }
+ else
+ word0(rv) -= P*Exp_msk1;
+ }
+ else {
+ adj = aadj1 * ulp(dval(rv));
+ dval(rv) += adj;
+ }
+#else /*Sudden_Underflow*/
+ /* Compute adj so that the IEEE rounding rules will
+ * correctly round rv + adj in some half-way cases.
+ * If rv * ulp(rv) is denormalized (i.e.,
+ * y <= (P-1)*Exp_msk1), we must adjust aadj to avoid
+ * trouble from bits lost to denormalization;
+ * example: 1.2e-307 .
+ */
+ if (y <= (P-1)*Exp_msk1 && aadj > 1.) {
+ aadj1 = (double)(int)(aadj + 0.5);
+ if (!dsign)
+ aadj1 = -aadj1;
+ }
+ adj = aadj1 * ulp(dval(rv));
+ dval(rv) += adj;
+#endif /*Sudden_Underflow*/
+#endif /*Avoid_Underflow*/
+ }
+ z = word0(rv) & Exp_mask;
+#ifndef SET_INEXACT
+#ifdef Avoid_Underflow
+ if (!scale)
+#endif
+ if (y == z) {
+ /* Can we stop now? */
+ L = (Long)aadj;
+ aadj -= L;
+ /* The tolerances below are conservative. */
+ if (dsign || word1(rv) || word0(rv) & Bndry_mask) {
+ if (aadj < .4999999 || aadj > .5000001)
+ break;
+ }
+ else if (aadj < .4999999/FLT_RADIX)
+ break;
+ }
+#endif
+ cont:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(delta);
+ }
+#ifdef SET_INEXACT
+ if (inexact) {
+ if (!oldinexact) {
+ word0(rv0) = Exp_1 + (70 << Exp_shift);
+ word1(rv0) = 0;
+ dval(rv0) += 1.;
+ }
+ }
+ else if (!oldinexact)
+ clear_inexact();
+#endif
+#ifdef Avoid_Underflow
+ if (scale) {
+ word0(rv0) = Exp_1 - 2*P*Exp_msk1;
+ word1(rv0) = 0;
+ dval(rv) *= dval(rv0);
+#ifndef NO_ERRNO
+ /* try to avoid the bug of testing an 8087 register value */
+ if (word0(rv) == 0 && word1(rv) == 0)
+ errno = ERANGE;
+#endif
+ }
+#endif /* Avoid_Underflow */
+#ifdef SET_INEXACT
+ if (inexact && !(word0(rv) & Exp_mask)) {
+ /* set underflow bit */
+ dval(rv0) = 1e-300;
+ dval(rv0) *= dval(rv0);
+ }
+#endif
+ retfree:
+ Bfree(bb);
+ Bfree(bd);
+ Bfree(bs);
+ Bfree(bd0);
+ Bfree(delta);
+ ret:
+ if (se)
+ *se = (char *)s;
+ return sign ? -dval(rv) : dval(rv);
+ }
+
+ static int
+quorem
+#ifdef KR_headers
+ (b, S) Bigint *b, *S;
+#else
+ (Bigint *b, Bigint *S)
+#endif
+{
+ int n;
+ ULong *bx, *bxe, q, *sx, *sxe;
+#ifdef ULLong
+ ULLong borrow, carry, y, ys;
+#else
+ ULong borrow, carry, y, ys;
+#ifdef Pack_32
+ ULong si, z, zs;
+#endif
+#endif
+
+ n = S->wds;
+#ifdef DEBUG
+ /*debug*/ if (b->wds > n)
+ /*debug*/ Bug("oversize b in quorem");
+#endif
+ if (b->wds < n)
+ return 0;
+ sx = S->x;
+ sxe = sx + --n;
+ bx = b->x;
+ bxe = bx + n;
+ q = *bxe / (*sxe + 1); /* ensure q <= true quotient */
+#ifdef DEBUG
+ /*debug*/ if (q > 9)
+ /*debug*/ Bug("oversized quotient in quorem");
+#endif
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef ULLong
+ ys = *sx++ * (ULLong)q + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = (ULong)y & FFFFFFFF;
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) * q + carry;
+ zs = (si >> 16) * q + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ * q + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ }
+ while(sx <= sxe);
+ if (!*bxe) {
+ bx = b->x;
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ if (cmp(b, S) >= 0) {
+ q++;
+ borrow = 0;
+ carry = 0;
+ bx = b->x;
+ sx = S->x;
+ do {
+#ifdef ULLong
+ ys = *sx++ + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & FFFFFFFF) - borrow;
+ borrow = y >> 32 & (ULong)1;
+ *bx++ = (ULong)y & FFFFFFFF;
+#else
+#ifdef Pack_32
+ si = *sx++;
+ ys = (si & 0xffff) + carry;
+ zs = (si >> 16) + (ys >> 16);
+ carry = zs >> 16;
+ y = (*bx & 0xffff) - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ z = (*bx >> 16) - (zs & 0xffff) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(bx, z, y);
+#else
+ ys = *sx++ + carry;
+ carry = ys >> 16;
+ y = *bx - (ys & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *bx++ = y & 0xffff;
+#endif
+#endif
+ }
+ while(sx <= sxe);
+ bx = b->x;
+ bxe = bx + n;
+ if (!*bxe) {
+ while(--bxe > bx && !*bxe)
+ --n;
+ b->wds = n;
+ }
+ }
+ return q;
+ }
+
+#ifndef MULTIPLE_THREADS
+ static char *dtoa_result;
+#endif
+
+ static char *
+#ifdef KR_headers
+rv_alloc(i) int i;
+#else
+rv_alloc(int i)
+#endif
+{
+ int j, k, *r;
+
+ j = sizeof(ULong);
+ for(k = 0;
+ sizeof(Bigint) - sizeof(ULong) - sizeof(int) + j <= (unsigned)i;
+ j <<= 1)
+ k++;
+ r = (int*)Balloc(k);
+ *r = k;
+ return
+#ifndef MULTIPLE_THREADS
+ dtoa_result =
+#endif
+ (char *)(r+1);
+ }
+
+ static char *
+#ifdef KR_headers
+nrv_alloc(s, rve, n) char *s, **rve; int n;
+#else
+nrv_alloc(CONST_ char *s, char **rve, int n)
+#endif
+{
+ char *rv, *t;
+
+ t = rv = rv_alloc(n);
+ while((*t = *s++)) t++;
+ if (rve)
+ *rve = t;
+ return rv;
+ }
+
+/* freedtoa(s) must be used to free values s returned by dtoa
+ * when MULTIPLE_THREADS is #defined. It should be used in all cases,
+ * but for consistency with earlier versions of dtoa, it is optional
+ * when MULTIPLE_THREADS is not defined.
+ */
+
+ void
+#ifdef KR_headers
+freedtoa(s) char *s;
+#else
+freedtoa(char *s)
+#endif
+{
+ Bigint *b = (Bigint *)((int *)s - 1);
+ b->maxwds = 1 << (b->k = *(int*)b);
+ Bfree(b);
+#ifndef MULTIPLE_THREADS
+ if (s == dtoa_result)
+ dtoa_result = 0;
+#endif
+ }
+
+/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
+ *
+ * Inspired by "How to Print Floating-Point Numbers Accurately" by
+ * Guy L. Steele, Jr. and Jon L. White [Proc. ACM SIGPLAN '90, pp. 92-101].
+ *
+ * Modifications:
+ * 1. Rather than iterating, we use a simple numeric overestimate
+ * to determine k = floor(log10(d)). We scale relevant
+ * quantities using O(log2(k)) rather than O(k) multiplications.
+ * 2. For some modes > 2 (corresponding to ecvt and fcvt), we don't
+ * try to generate digits strictly left to right. Instead, we
+ * compute with fewer bits and propagate the carry if necessary
+ * when rounding the final digit up. This is often faster.
+ * 3. Under the assumption that input will be rounded nearest,
+ * mode 0 renders 1e23 as 1e23 rather than 9.999999999999999e22.
+ * That is, we allow equality in stopping tests when the
+ * round-nearest rule will give the same floating-point value
+ * as would satisfaction of the stopping test with strict
+ * inequality.
+ * 4. We remove common factors of powers of 2 from relevant
+ * quantities.
+ * 5. When converting floating-point integers less than 1e16,
+ * we use floating-point arithmetic rather than resorting
+ * to multiple-precision integers.
+ * 6. When asked to produce fewer than 15 digits, we first try
+ * to get by with floating-point arithmetic; we resort to
+ * multiple-precision integer arithmetic only if we cannot
+ * guarantee that the floating-point calculation has given
+ * the correctly rounded result. For k requested digits and
+ * "uniformly" distributed input, the probability is
+ * something like 10^(k-15) that we must resort to the Long
+ * calculation.
+ */
+
+ char *
+dtoa
+#ifdef KR_headers
+ (d, mode, ndigits, decpt, sign, rve)
+ double d; int mode, ndigits, *decpt, *sign; char **rve;
+#else
+ (double d, int mode, int ndigits, int *decpt, int *sign, char **rve)
+#endif
+{
+ /* Arguments ndigits, decpt, sign are similar to those
+ of ecvt and fcvt; trailing zeros are suppressed from
+ the returned string. If not null, *rve is set to point
+ to the end of the return value. If d is +-Infinity or NaN,
+ then *decpt is set to 9999.
+
+ mode:
+ 0 ==> shortest string that yields d when read in
+ and rounded to nearest.
+ 1 ==> like 0, but with Steele & White stopping rule;
+ e.g. with IEEE P754 arithmetic , mode 0 gives
+ 1e23 whereas mode 1 gives 9.999999999999999e22.
+ 2 ==> max(1,ndigits) significant digits. This gives a
+ return value similar to that of ecvt, except
+ that trailing zeros are suppressed.
+ 3 ==> through ndigits past the decimal point. This
+ gives a return value similar to that from fcvt,
+ except that trailing zeros are suppressed, and
+ ndigits can be negative.
+ 4,5 ==> similar to 2 and 3, respectively, but (in
+ round-nearest mode) with the tests of mode 0 to
+ possibly return a shorter string that rounds to d.
+ With IEEE arithmetic and compilation with
+ -DHonor_FLT_ROUNDS, modes 4 and 5 behave the same
+ as modes 2 and 3 when FLT_ROUNDS != 1.
+ 6-9 ==> Debugging modes similar to mode - 4: don't try
+ fast floating-point estimate (if applicable).
+
+ Values of mode other than 0-9 are treated as mode 0.
+
+ Sufficient space is allocated to the return value
+ to hold the suppressed trailing zeros.
+ */
+
+ int bbits, b2, b5, be, dig, i, ieps, ilim = 0, ilim0, ilim1 = 0,
+ j, j1, k, k0, k_check, leftright, m2, m5, s2, s5,
+ spec_case, try_quick;
+ Long L;
+#ifndef Sudden_Underflow
+ int denorm;
+ ULong x;
+#endif
+ Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S;
+ double d2, ds, eps;
+ char *s, *s0;
+#ifdef Honor_FLT_ROUNDS
+ int rounding;
+#endif
+#ifdef SET_INEXACT
+ int inexact, oldinexact;
+#endif
+
+#ifndef MULTIPLE_THREADS
+ if (dtoa_result) {
+ freedtoa(dtoa_result);
+ dtoa_result = 0;
+ }
+#endif
+
+ if (word0(d) & Sign_bit) {
+ /* set sign for everything, including 0's and NaNs */
+ *sign = 1;
+ word0(d) &= ~Sign_bit; /* clear sign bit */
+ }
+ else
+ *sign = 0;
+
+#if defined(IEEE_Arith) + defined(VAX)
+#ifdef IEEE_Arith
+ if ((word0(d) & Exp_mask) == Exp_mask)
+#else
+ if (word0(d) == 0x8000)
+#endif
+ {
+ /* Infinity or NaN */
+ *decpt = 9999;
+#ifdef IEEE_Arith
+ if (!word1(d) && !(word0(d) & 0xfffff))
+ return nrv_alloc("Infinity", rve, 8);
+#endif
+ return nrv_alloc("NaN", rve, 3);
+ }
+#endif
+#ifdef IBM
+ dval(d) += 0; /* normalize */
+#endif
+ if (!dval(d)) {
+ *decpt = 1;
+ return nrv_alloc("0", rve, 1);
+ }
+
+#ifdef SET_INEXACT
+ try_quick = oldinexact = get_inexact();
+ inexact = 1;
+#endif
+#ifdef Honor_FLT_ROUNDS
+ if ((rounding = Flt_Rounds) >= 2) {
+ if (*sign)
+ rounding = rounding == 2 ? 0 : 2;
+ else
+ if (rounding != 2)
+ rounding = 0;
+ }
+#endif
+
+ b = d2b(dval(d), &be, &bbits);
+#ifdef Sudden_Underflow
+ i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1));
+#else
+ if ((i = (int)(word0(d) >> Exp_shift1 & (Exp_mask>>Exp_shift1)))) {
+#endif
+ dval(d2) = dval(d);
+ word0(d2) &= Frac_mask1;
+ word0(d2) |= Exp_11;
+#ifdef IBM
+ if (j = 11 - hi0bits(word0(d2) & Frac_mask))
+ dval(d2) /= 1 << j;
+#endif
+
+ /* log(x) ~=~ log(1.5) + (x-1.5)/1.5
+ * log10(x) = log(x) / log(10)
+ * ~=~ log(1.5)/log(10) + (x-1.5)/(1.5*log(10))
+ * log10(d) = (i-Bias)*log(2)/log(10) + log10(d2)
+ *
+ * This suggests computing an approximation k to log10(d) by
+ *
+ * k = (i - Bias)*0.301029995663981
+ * + ( (d2-1.5)*0.289529654602168 + 0.176091259055681 );
+ *
+ * We want k to be too large rather than too small.
+ * The error in the first-order Taylor series approximation
+ * is in our favor, so we just round up the constant enough
+ * to compensate for any error in the multiplication of
+ * (i - Bias) by 0.301029995663981; since |i - Bias| <= 1077,
+ * and 1077 * 0.30103 * 2^-52 ~=~ 7.2e-14,
+ * adding 1e-13 to the constant term more than suffices.
+ * Hence we adjust the constant term to 0.1760912590558.
+ * (We could get a more accurate k by invoking log10,
+ * but this is probably not worthwhile.)
+ */
+
+ i -= Bias;
+#ifdef IBM
+ i <<= 2;
+ i += j;
+#endif
+#ifndef Sudden_Underflow
+ denorm = 0;
+ }
+ else {
+ /* d is denormalized */
+
+ i = bbits + be + (Bias + (P-1) - 1);
+ x = i > 32 ? word0(d) << 64 - i | word1(d) >> i - 32
+ : word1(d) << 32 - i;
+ dval(d2) = x;
+ word0(d2) -= 31*Exp_msk1; /* adjust exponent */
+ i -= (Bias + (P-1) - 1) + 1;
+ denorm = 1;
+ }
+#endif
+ ds = (dval(d2)-1.5)*0.289529654602168 + 0.1760912590558 + i*0.301029995663981;
+ k = (int)ds;
+ if (ds < 0. && ds != k)
+ k--; /* want k = floor(ds) */
+ k_check = 1;
+ if (k >= 0 && k <= Ten_pmax) {
+ if (dval(d) < tens[k])
+ k--;
+ k_check = 0;
+ }
+ j = bbits - i - 1;
+ if (j >= 0) {
+ b2 = 0;
+ s2 = j;
+ }
+ else {
+ b2 = -j;
+ s2 = 0;
+ }
+ if (k >= 0) {
+ b5 = 0;
+ s5 = k;
+ s2 += k;
+ }
+ else {
+ b2 -= k;
+ b5 = -k;
+ s5 = 0;
+ }
+ if (mode < 0 || mode > 9)
+ mode = 0;
+
+#ifndef SET_INEXACT
+#ifdef Check_FLT_ROUNDS
+ try_quick = Rounding == 1;
+#else
+ try_quick = 1;
+#endif
+#endif /*SET_INEXACT*/
+
+ if (mode > 5) {
+ mode -= 4;
+ try_quick = 0;
+ }
+ leftright = 1;
+ switch(mode) {
+ case 0:
+ case 1:
+ ilim = ilim1 = -1;
+ i = 18;
+ ndigits = 0;
+ break;
+ case 2:
+ leftright = 0;
+ /* no break */
+ case 4:
+ if (ndigits <= 0)
+ ndigits = 1;
+ ilim = ilim1 = i = ndigits;
+ break;
+ case 3:
+ leftright = 0;
+ /* no break */
+ case 5:
+ i = ndigits + k + 1;
+ ilim = i;
+ ilim1 = i - 1;
+ if (i <= 0)
+ i = 1;
+ }
+ s = s0 = rv_alloc(i);
+
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1 && rounding != 1)
+ leftright = 0;
+#endif
+
+ if (ilim >= 0 && ilim <= Quick_max && try_quick) {
+
+ /* Try to get by with floating-point arithmetic. */
+
+ i = 0;
+ dval(d2) = dval(d);
+ k0 = k;
+ ilim0 = ilim;
+ ieps = 2; /* conservative */
+ if (k > 0) {
+ ds = tens[k&0xf];
+ j = k >> 4;
+ if (j & Bletch) {
+ /* prevent overflows */
+ j &= Bletch - 1;
+ dval(d) /= bigtens[n_bigtens-1];
+ ieps++;
+ }
+ for(; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ ds *= bigtens[i];
+ }
+ dval(d) /= ds;
+ }
+ else if ((j1 = -k)) {
+ dval(d) *= tens[j1 & 0xf];
+ for(j = j1 >> 4; j; j >>= 1, i++)
+ if (j & 1) {
+ ieps++;
+ dval(d) *= bigtens[i];
+ }
+ }
+ if (k_check && dval(d) < 1. && ilim > 0) {
+ if (ilim1 <= 0)
+ goto fast_failed;
+ ilim = ilim1;
+ k--;
+ dval(d) *= 10.;
+ ieps++;
+ }
+ dval(eps) = ieps*dval(d) + 7.;
+ word0(eps) -= (P-1)*Exp_msk1;
+ if (ilim == 0) {
+ S = mhi = 0;
+ dval(d) -= 5.;
+ if (dval(d) > dval(eps))
+ goto one_digit;
+ if (dval(d) < -dval(eps))
+ goto no_digits;
+ goto fast_failed;
+ }
+#ifndef No_leftright
+ if (leftright) {
+ /* Use Steele & White method of only
+ * generating digits needed.
+ */
+ dval(eps) = 0.5/tens[ilim-1] - dval(eps);
+ for(i = 0;;) {
+ L = (long int)dval(d);
+ dval(d) -= L;
+ *s++ = '0' + (int)L;
+ if (dval(d) < dval(eps))
+ goto ret1;
+ if (1. - dval(d) < dval(eps))
+ goto bump_up;
+ if (++i >= ilim)
+ break;
+ dval(eps) *= 10.;
+ dval(d) *= 10.;
+ }
+ }
+ else {
+#endif
+ /* Generate ilim digits, then fix them up. */
+ dval(eps) *= tens[ilim-1];
+ for(i = 1;; i++, dval(d) *= 10.) {
+ L = (Long)(dval(d));
+ if (!(dval(d) -= L))
+ ilim = i;
+ *s++ = '0' + (int)L;
+ if (i == ilim) {
+ if (dval(d) > 0.5 + dval(eps))
+ goto bump_up;
+ else if (dval(d) < 0.5 - dval(eps)) {
+ while (*--s == '0') { }
+ s++;
+ goto ret1;
+ }
+ break;
+ }
+ }
+#ifndef No_leftright
+ }
+#endif
+ fast_failed:
+ s = s0;
+ dval(d) = dval(d2);
+ k = k0;
+ ilim = ilim0;
+ }
+
+ /* Do we have a "small" integer? */
+
+ if (be >= 0 && k <= Int_max) {
+ /* Yes. */
+ ds = tens[k];
+ if (ndigits < 0 && ilim <= 0) {
+ S = mhi = 0;
+ if (ilim < 0 || dval(d) <= 5*ds)
+ goto no_digits;
+ goto one_digit;
+ }
+ for(i = 1;; i++, dval(d) *= 10.) {
+ L = (Long)(dval(d) / ds);
+ dval(d) -= L*ds;
+#ifdef Check_FLT_ROUNDS
+ /* If FLT_ROUNDS == 2, L will usually be high by 1 */
+ if (dval(d) < 0) {
+ L--;
+ dval(d) += ds;
+ }
+#endif
+ *s++ = '0' + (int)L;
+ if (!dval(d)) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ break;
+ }
+ if (i == ilim) {
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch(rounding) {
+ case 0: goto ret1;
+ case 2: goto bump_up;
+ }
+#endif
+ dval(d) += dval(d);
+ if (dval(d) > ds || dval(d) == ds && L & 1) {
+ bump_up:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s = '0';
+ break;
+ }
+ ++*s++;
+ }
+ break;
+ }
+ }
+ goto ret1;
+ }
+
+ m2 = b2;
+ m5 = b5;
+ mhi = mlo = 0;
+ if (leftright) {
+ i =
+#ifndef Sudden_Underflow
+ denorm ? be + (Bias + (P-1) - 1 + 1) :
+#endif
+#ifdef IBM
+ 1 + 4*P - 3 - bbits + ((bbits + be - 1) & 3);
+#else
+ 1 + P - bbits;
+#endif
+ b2 += i;
+ s2 += i;
+ mhi = i2b(1);
+ }
+ if (m2 > 0 && s2 > 0) {
+ i = m2 < s2 ? m2 : s2;
+ b2 -= i;
+ m2 -= i;
+ s2 -= i;
+ }
+ if (b5 > 0) {
+ if (leftright) {
+ if (m5 > 0) {
+ mhi = pow5mult(mhi, m5);
+ b1 = mult(mhi, b);
+ Bfree(b);
+ b = b1;
+ }
+ if ((j = b5 - m5))
+ b = pow5mult(b, j);
+ }
+ else
+ b = pow5mult(b, b5);
+ }
+ S = i2b(1);
+ if (s5 > 0)
+ S = pow5mult(S, s5);
+
+ /* Check for special case that d is a normalized power of 2. */
+
+ spec_case = 0;
+ if ((mode < 2 || leftright)
+#ifdef Honor_FLT_ROUNDS
+ && rounding == 1
+#endif
+ ) {
+ if (!word1(d) && !(word0(d) & Bndry_mask)
+#ifndef Sudden_Underflow
+ && word0(d) & (Exp_mask & ~Exp_msk1)
+#endif
+ ) {
+ /* The special case */
+ b2 += Log2P;
+ s2 += Log2P;
+ spec_case = 1;
+ }
+ }
+
+ /* Arrange for convenient computation of quotients:
+ * shift left if necessary so divisor has 4 leading 0 bits.
+ *
+ * Perhaps we should just compute leading 28 bits of S once
+ * and for all and pass them and a shift to quorem, so it
+ * can do shifts and ors to compute the numerator for q.
+ */
+#ifdef Pack_32
+ if ((i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0x1f))
+ i = 32 - i;
+#else
+ if (i = ((s5 ? 32 - hi0bits(S->x[S->wds-1]) : 1) + s2) & 0xf)
+ i = 16 - i;
+#endif
+ if (i > 4) {
+ i -= 4;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ else if (i < 4) {
+ i += 28;
+ b2 += i;
+ m2 += i;
+ s2 += i;
+ }
+ if (b2 > 0)
+ b = lshift(b, b2);
+ if (s2 > 0)
+ S = lshift(S, s2);
+ if (k_check) {
+ if (cmp(b,S) < 0) {
+ k--;
+ b = multadd(b, 10, 0); /* we botched the k estimate */
+ if (leftright)
+ mhi = multadd(mhi, 10, 0);
+ ilim = ilim1;
+ }
+ }
+ if (ilim <= 0 && (mode == 3 || mode == 5)) {
+ if (ilim < 0 || cmp(b,S = multadd(S,5,0)) <= 0) {
+ /* no digits, fcvt style */
+ no_digits:
+ k = -1 - ndigits;
+ goto ret;
+ }
+ one_digit:
+ *s++ = '1';
+ k++;
+ goto ret;
+ }
+ if (leftright) {
+ if (m2 > 0)
+ mhi = lshift(mhi, m2);
+
+ /* Compute mlo -- check for special case
+ * that d is a normalized power of 2.
+ */
+
+ mlo = mhi;
+ if (spec_case) {
+ mhi = Balloc(mhi->k);
+ Bcopy(mhi, mlo);
+ mhi = lshift(mhi, Log2P);
+ }
+
+ for(i = 1;;i++) {
+ dig = quorem(b,S) + '0';
+ /* Do we yet have the shortest decimal string
+ * that will round to d?
+ */
+ j = cmp(b, mlo);
+ delta = diff(S, mhi);
+ j1 = delta->sign ? 1 : cmp(b, delta);
+ Bfree(delta);
+#ifndef ROUND_BIASED
+ if (j1 == 0 && mode != 1 && !(word1(d) & 1)
+#ifdef Honor_FLT_ROUNDS
+ && rounding >= 1
+#endif
+ ) {
+ if (dig == '9')
+ goto round_9_up;
+ if (j > 0)
+ dig++;
+#ifdef SET_INEXACT
+ else if (!b->x[0] && b->wds <= 1)
+ inexact = 0;
+#endif
+ *s++ = dig;
+ goto ret;
+ }
+#endif
+ if (j < 0 || j == 0 && mode != 1
+#ifndef ROUND_BIASED
+ && !(word1(d) & 1)
+#endif
+ ) {
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto accept_dig;
+ }
+#ifdef Honor_FLT_ROUNDS
+ if (mode > 1)
+ switch(rounding) {
+ case 0: goto accept_dig;
+ case 2: goto keep_dig;
+ }
+#endif /*Honor_FLT_ROUNDS*/
+ if (j1 > 0) {
+ b = lshift(b, 1);
+ j1 = cmp(b, S);
+ if ((j1 > 0 || j1 == 0 && dig & 1)
+ && dig++ == '9')
+ goto round_9_up;
+ }
+ accept_dig:
+ *s++ = dig;
+ goto ret;
+ }
+ if (j1 > 0) {
+#ifdef Honor_FLT_ROUNDS
+ if (!rounding)
+ goto accept_dig;
+#endif
+ if (dig == '9') { /* possible if i == 1 */
+ round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+#ifdef Honor_FLT_ROUNDS
+ keep_dig:
+#endif
+ *s++ = dig;
+ if (i == ilim)
+ break;
+ b = multadd(b, 10, 0);
+ if (mlo == mhi)
+ mlo = mhi = multadd(mhi, 10, 0);
+ else {
+ mlo = multadd(mlo, 10, 0);
+ mhi = multadd(mhi, 10, 0);
+ }
+ }
+ }
+ else
+ for(i = 1;; i++) {
+ *s++ = dig = quorem(b,S) + '0';
+ if (!b->x[0] && b->wds <= 1) {
+#ifdef SET_INEXACT
+ inexact = 0;
+#endif
+ goto ret;
+ }
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ }
+
+ /* Round off last digit */
+
+#ifdef Honor_FLT_ROUNDS
+ switch(rounding) {
+ case 0: goto trimzeros;
+ case 2: goto roundoff;
+ }
+#endif
+ b = lshift(b, 1);
+ j = cmp(b, S);
+ if (j > 0 || j == 0 && dig & 1) {
+ roundoff:
+ while(*--s == '9')
+ if (s == s0) {
+ k++;
+ *s++ = '1';
+ goto ret;
+ }
+ ++*s++;
+ }
+ else {
+#ifdef Honor_FLT_ROUNDS
+trimzeros:
+#endif
+ while (*--s == '0') { }
+ s++;
+ }
+ ret:
+ Bfree(S);
+ if (mhi) {
+ if (mlo && mlo != mhi)
+ Bfree(mlo);
+ Bfree(mhi);
+ }
+ ret1:
+#ifdef SET_INEXACT
+ if (inexact) {
+ if (!oldinexact) {
+ word0(d) = Exp_1 + (70 << Exp_shift);
+ word1(d) = 0;
+ dval(d) += 1.;
+ }
+ }
+ else if (!oldinexact)
+ clear_inexact();
+#endif
+ Bfree(b);
+ *s = 0;
+ *decpt = k + 1;
+ if (rve)
+ *rve = s;
+ return s0;
+ }
+#ifdef __cplusplus
+}
+#endif
diff --git a/JavaScriptCore/kjs/dtoa.h b/JavaScriptCore/kjs/dtoa.h
new file mode 100644
index 0000000..79ff828
--- /dev/null
+++ b/JavaScriptCore/kjs/dtoa.h
@@ -0,0 +1,31 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _KJS_DTOA_H_
+#define _KJS_DTOA_H_
+
+extern "C" double kjs_strtod(const char *s00, char **se);
+extern "C" char *kjs_dtoa(double d, int mode, int ndigits,
+ int *decpt, int *sign, char **rve);
+extern "C" void kjs_freedtoa(char *s);
+
+#endif /* _KJS_DTOA_H */
diff --git a/JavaScriptCore/kjs/error_object.cpp b/JavaScriptCore/kjs/error_object.cpp
new file mode 100644
index 0000000..75ef0ba
--- /dev/null
+++ b/JavaScriptCore/kjs/error_object.cpp
@@ -0,0 +1,153 @@
+/*
+ * 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 "error_object.h"
+
+#include "JSGlobalObject.h"
+#include "object.h"
+#include "operations.h"
+#include "types.h"
+#include "value.h"
+
+namespace KJS {
+
+// ------------------------------ ErrorInstance ----------------------------
+
+const ClassInfo ErrorInstance::info = { "Error", 0, 0 };
+
+ErrorInstance::ErrorInstance(JSObject* prototype)
+ : JSObject(prototype)
+{
+}
+
+// ------------------------------ ErrorPrototype ----------------------------
+
+// ECMA 15.9.4
+ErrorPrototype::ErrorPrototype(ExecState* exec, ObjectPrototype* objectPrototype, FunctionPrototype* functionPrototype)
+ : ErrorInstance(objectPrototype)
+{
+ // The constructor will be added later in ErrorObjectImp's constructor
+
+ putDirect(exec->propertyNames().name, jsString("Error"), DontEnum);
+ putDirect(exec->propertyNames().message, jsString("Unknown error"), DontEnum);
+
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toString, errorProtoFuncToString), DontEnum);
+}
+
+JSValue* errorProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ UString s = "Error";
+
+ JSValue* v = thisObj->get(exec, exec->propertyNames().name);
+ if (!v->isUndefined())
+ s = v->toString(exec);
+
+ v = thisObj->get(exec, exec->propertyNames().message);
+ if (!v->isUndefined())
+ // Mozilla compatible format
+ s += ": " + v->toString(exec);
+
+ return jsString(s);
+}
+
+// ------------------------------ ErrorObjectImp -------------------------------
+
+ErrorObjectImp::ErrorObjectImp(ExecState* exec, FunctionPrototype* funcProto, ErrorPrototype* errorProto)
+ : InternalFunctionImp(funcProto, errorProto->classInfo()->className)
+{
+ // ECMA 15.11.3.1 Error.prototype
+ putDirect(exec->propertyNames().prototype, errorProto, DontEnum|DontDelete|ReadOnly);
+ putDirect(exec->propertyNames().length, jsNumber(1), DontDelete|ReadOnly|DontEnum);
+}
+
+bool ErrorObjectImp::implementsConstruct() const
+{
+ return true;
+}
+
+// ECMA 15.9.3
+JSObject* ErrorObjectImp::construct(ExecState* exec, const List& args)
+{
+ JSObject* proto = static_cast<JSObject*>(exec->lexicalGlobalObject()->errorPrototype());
+ JSObject* imp = new ErrorInstance(proto);
+ JSObject* obj(imp);
+
+ if (!args[0]->isUndefined())
+ imp->putDirect(exec->propertyNames().message, jsString(args[0]->toString(exec)));
+
+ return obj;
+}
+
+// ECMA 15.9.2
+JSValue* ErrorObjectImp::callAsFunction(ExecState* exec, JSObject* /*thisObj*/, const List& args)
+{
+ // "Error()" gives the sames result as "new Error()"
+ return construct(exec, args);
+}
+
+// ------------------------------ NativeErrorPrototype ----------------------
+
+NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, ErrorPrototype* errorProto, const UString& name, const UString& message)
+ : JSObject(errorProto)
+{
+ putDirect(exec->propertyNames().name, jsString(name), 0);
+ putDirect(exec->propertyNames().message, jsString(message), 0);
+}
+
+// ------------------------------ NativeErrorImp -------------------------------
+
+const ClassInfo NativeErrorImp::info = { "Function", &InternalFunctionImp::info, 0 };
+
+NativeErrorImp::NativeErrorImp(ExecState* exec, FunctionPrototype* funcProto, NativeErrorPrototype* prot)
+ : InternalFunctionImp(funcProto, Identifier(prot->getDirect(exec->propertyNames().name)->getString()))
+ , proto(prot)
+{
+ putDirect(exec->propertyNames().length, jsNumber(1), DontDelete|ReadOnly|DontEnum); // ECMA 15.11.7.5
+ putDirect(exec->propertyNames().prototype, proto, DontDelete|ReadOnly|DontEnum);
+}
+
+bool NativeErrorImp::implementsConstruct() const
+{
+ return true;
+}
+
+JSObject* NativeErrorImp::construct(ExecState* exec, const List& args)
+{
+ JSObject* imp = new ErrorInstance(proto);
+ JSObject* obj(imp);
+ if (!args[0]->isUndefined())
+ imp->putDirect(exec->propertyNames().message, jsString(args[0]->toString(exec)));
+ return obj;
+}
+
+JSValue* NativeErrorImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
+{
+ return construct(exec, args);
+}
+
+void NativeErrorImp::mark()
+{
+ JSObject::mark();
+ if (proto && !proto->marked())
+ proto->mark();
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/error_object.h b/JavaScriptCore/kjs/error_object.h
new file mode 100644
index 0000000..9734085
--- /dev/null
+++ b/JavaScriptCore/kjs/error_object.h
@@ -0,0 +1,77 @@
+/*
+ * 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 ERROR_OBJECT_H_
+#define ERROR_OBJECT_H_
+
+#include "function_object.h"
+
+namespace KJS {
+
+ class ErrorInstance : public JSObject {
+ public:
+ ErrorInstance(JSObject* prototype);
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+ };
+
+ class ErrorPrototype : public ErrorInstance {
+ public:
+ ErrorPrototype(ExecState*, ObjectPrototype*, FunctionPrototype*);
+ };
+
+ JSValue* errorProtoFuncToString(ExecState*, JSObject*, const List&);
+
+ class ErrorObjectImp : public InternalFunctionImp {
+ public:
+ ErrorObjectImp(ExecState*, FunctionPrototype*, ErrorPrototype*);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject* construct(ExecState*, const List&);
+
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+ };
+
+ class NativeErrorPrototype : public JSObject {
+ public:
+ NativeErrorPrototype(ExecState*, ErrorPrototype*, const UString& name, const UString& message);
+ };
+
+ class NativeErrorImp : public InternalFunctionImp {
+ public:
+ NativeErrorImp(ExecState*, FunctionPrototype*, NativeErrorPrototype*);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject* construct(ExecState*, const List&);
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+
+ virtual void mark();
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+
+ private:
+ JSObject* proto;
+ };
+
+} // namespace KJS
+
+#endif // ERROR_OBJECT_H_
diff --git a/JavaScriptCore/kjs/function.cpp b/JavaScriptCore/kjs/function.cpp
new file mode 100644
index 0000000..b996122
--- /dev/null
+++ b/JavaScriptCore/kjs/function.cpp
@@ -0,0 +1,894 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 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 "function.h"
+
+#include "Activation.h"
+#include "ExecState.h"
+#include "JSGlobalObject.h"
+#include "Parser.h"
+#include "PropertyNameArray.h"
+#include "debugger.h"
+#include "dtoa.h"
+#include "function_object.h"
+#include "internal.h"
+#include "lexer.h"
+#include "nodes.h"
+#include "operations.h"
+#include "scope_chain_mark.h"
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/unicode/UTF8.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace KJS {
+
+// ----------------------------- FunctionImp ----------------------------------
+
+const ClassInfo FunctionImp::info = { "Function", &InternalFunctionImp::info, 0 };
+
+FunctionImp::FunctionImp(ExecState* exec, const Identifier& name, FunctionBodyNode* b, const ScopeChain& sc)
+ : InternalFunctionImp(exec->lexicalGlobalObject()->functionPrototype(), name)
+ , body(b)
+ , _scope(sc)
+{
+}
+
+void FunctionImp::mark()
+{
+ InternalFunctionImp::mark();
+ _scope.mark();
+}
+
+JSValue* FunctionImp::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ FunctionExecState newExec(exec->dynamicGlobalObject(), thisObj, body.get(), exec, this, args);
+ JSValue* result = body->execute(&newExec);
+ if (newExec.completionType() == Throw) {
+ exec->setException(result);
+ return result;
+ }
+ if (newExec.completionType() == ReturnValue)
+ return result;
+ return jsUndefined();
+}
+
+JSValue* FunctionImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
+{
+ FunctionImp* thisObj = static_cast<FunctionImp*>(slot.slotBase());
+
+ for (ExecState* e = exec; e; e = e->callingExecState())
+ if (e->function() == thisObj) {
+ e->dynamicGlobalObject()->tearOffActivation(e, e != exec);
+ return e->activationObject()->get(exec, propertyName);
+ }
+
+ return jsNull();
+}
+
+JSValue* FunctionImp::callerGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot)
+{
+ FunctionImp* thisObj = static_cast<FunctionImp*>(slot.slotBase());
+ ExecState* e = exec;
+ while (e) {
+ if (e->function() == thisObj)
+ break;
+ e = e->callingExecState();
+ }
+
+ if (!e)
+ return jsNull();
+
+ ExecState* callingExecState = e->callingExecState();
+ if (!callingExecState)
+ return jsNull();
+
+ FunctionImp* callingFunction = callingExecState->function();
+ if (!callingFunction)
+ return jsNull();
+
+ return callingFunction;
+}
+
+JSValue* FunctionImp::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
+{
+ FunctionImp* thisObj = static_cast<FunctionImp*>(slot.slotBase());
+ return jsNumber(thisObj->body->parameters().size());
+}
+
+bool FunctionImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ // Find the arguments from the closest context.
+ if (propertyName == exec->propertyNames().arguments) {
+ slot.setCustom(this, argumentsGetter);
+ return true;
+ }
+
+ // Compute length of parameters.
+ if (propertyName == exec->propertyNames().length) {
+ slot.setCustom(this, lengthGetter);
+ return true;
+ }
+
+ if (propertyName == exec->propertyNames().caller) {
+ slot.setCustom(this, callerGetter);
+ return true;
+ }
+
+ return InternalFunctionImp::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+void FunctionImp::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
+{
+ if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
+ return;
+ InternalFunctionImp::put(exec, propertyName, value);
+}
+
+bool FunctionImp::deleteProperty(ExecState* exec, const Identifier& propertyName)
+{
+ if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
+ return false;
+ return InternalFunctionImp::deleteProperty(exec, propertyName);
+}
+
+/* Returns the parameter name corresponding to the given index. eg:
+ * function f1(x, y, z): getParameterName(0) --> x
+ *
+ * If a name appears more than once, only the last index at which
+ * it appears associates with it. eg:
+ * function f2(x, x): getParameterName(0) --> null
+ */
+Identifier FunctionImp::getParameterName(int index)
+{
+ Vector<Identifier>& parameters = body->parameters();
+
+ if (static_cast<size_t>(index) >= body->parameters().size())
+ return CommonIdentifiers::shared()->nullIdentifier;
+
+ Identifier name = parameters[index];
+
+ // Are there any subsequent parameters with the same name?
+ size_t size = parameters.size();
+ for (size_t i = index + 1; i < size; ++i)
+ if (parameters[i] == name)
+ return CommonIdentifiers::shared()->nullIdentifier;
+
+ return name;
+}
+
+// ECMA 13.2.2 [[Construct]]
+JSObject* FunctionImp::construct(ExecState* exec, const List& args)
+{
+ JSObject* proto;
+ JSValue* p = get(exec, exec->propertyNames().prototype);
+ if (p->isObject())
+ proto = static_cast<JSObject*>(p);
+ else
+ proto = exec->lexicalGlobalObject()->objectPrototype();
+
+ JSObject* obj(new JSObject(proto));
+
+ JSValue* res = call(exec,obj,args);
+
+ if (res->isObject())
+ return static_cast<JSObject*>(res);
+ else
+ return obj;
+}
+
+// ------------------------------ IndexToNameMap ---------------------------------
+
+// We map indexes in the arguments array to their corresponding argument names.
+// Example: function f(x, y, z): arguments[0] = x, so we map 0 to Identifier("x").
+
+// Once we have an argument name, we can get and set the argument's value in the
+// activation object.
+
+// We use Identifier::null to indicate that a given argument's value
+// isn't stored in the activation object.
+
+IndexToNameMap::IndexToNameMap(FunctionImp* func, const List& args)
+{
+ _map = new Identifier[args.size()];
+ this->size = args.size();
+
+ int i = 0;
+ List::const_iterator end = args.end();
+ for (List::const_iterator it = args.begin(); it != end; ++i, ++it)
+ _map[i] = func->getParameterName(i); // null if there is no corresponding parameter
+}
+
+IndexToNameMap::~IndexToNameMap() {
+ delete [] _map;
+}
+
+bool IndexToNameMap::isMapped(const Identifier& index) const
+{
+ bool indexIsNumber;
+ int indexAsNumber = index.toUInt32(&indexIsNumber);
+
+ if (!indexIsNumber)
+ return false;
+
+ if (indexAsNumber >= size)
+ return false;
+
+ if (_map[indexAsNumber].isNull())
+ return false;
+
+ return true;
+}
+
+void IndexToNameMap::unMap(const Identifier& index)
+{
+ bool indexIsNumber;
+ int indexAsNumber = index.toUInt32(&indexIsNumber);
+
+ ASSERT(indexIsNumber && indexAsNumber < size);
+
+ _map[indexAsNumber] = CommonIdentifiers::shared()->nullIdentifier;
+}
+
+Identifier& IndexToNameMap::operator[](int index)
+{
+ return _map[index];
+}
+
+Identifier& IndexToNameMap::operator[](const Identifier& index)
+{
+ bool indexIsNumber;
+ int indexAsNumber = index.toUInt32(&indexIsNumber);
+
+ ASSERT(indexIsNumber && indexAsNumber < size);
+
+ return (*this)[indexAsNumber];
+}
+
+// ------------------------------ Arguments ---------------------------------
+
+const ClassInfo Arguments::info = { "Arguments", 0, 0 };
+
+// ECMA 10.1.8
+Arguments::Arguments(ExecState* exec, FunctionImp* func, const List& args, ActivationImp* act)
+ : JSObject(exec->lexicalGlobalObject()->objectPrototype())
+ , _activationObject(act)
+ , indexToNameMap(func, args)
+{
+ putDirect(exec->propertyNames().callee, func, DontEnum);
+ putDirect(exec->propertyNames().length, args.size(), DontEnum);
+
+ int i = 0;
+ List::const_iterator end = args.end();
+ for (List::const_iterator it = args.begin(); it != end; ++it, ++i) {
+ Identifier name = Identifier::from(i);
+ if (!indexToNameMap.isMapped(name))
+ putDirect(name, *it, DontEnum);
+ }
+}
+
+void Arguments::mark()
+{
+ JSObject::mark();
+ if (_activationObject && !_activationObject->marked())
+ _activationObject->mark();
+}
+
+JSValue* Arguments::mappedIndexGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
+{
+ Arguments* thisObj = static_cast<Arguments*>(slot.slotBase());
+ return thisObj->_activationObject->get(exec, thisObj->indexToNameMap[propertyName]);
+}
+
+bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (indexToNameMap.isMapped(propertyName)) {
+ slot.setCustom(this, mappedIndexGetter);
+ return true;
+ }
+
+ return JSObject::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+void Arguments::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
+{
+ if (indexToNameMap.isMapped(propertyName))
+ _activationObject->put(exec, indexToNameMap[propertyName], value);
+ else
+ JSObject::put(exec, propertyName, value);
+}
+
+bool Arguments::deleteProperty(ExecState* exec, const Identifier& propertyName)
+{
+ if (indexToNameMap.isMapped(propertyName)) {
+ indexToNameMap.unMap(propertyName);
+ return true;
+ } else {
+ return JSObject::deleteProperty(exec, propertyName);
+ }
+}
+
+// ------------------------------ ActivationImp --------------------------------
+
+const ClassInfo ActivationImp::info = { "Activation", 0, 0 };
+
+ActivationImp::ActivationImp(const ActivationData& oldData, bool leaveRelic)
+{
+ JSVariableObject::d = new ActivationData(oldData);
+ d()->leftRelic = leaveRelic;
+}
+
+ActivationImp::~ActivationImp()
+{
+ if (!d()->isOnStack)
+ delete d();
+}
+
+void ActivationImp::init(ExecState* exec)
+{
+ d()->symbolTable = &exec->function()->body->symbolTable();
+ d()->exec = exec;
+ d()->function = exec->function();
+ d()->argumentsObject = 0;
+}
+
+JSValue* ActivationImp::argumentsGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot)
+{
+ ActivationImp* thisObj = static_cast<ActivationImp*>(slot.slotBase());
+
+ if (!thisObj->d()->argumentsObject)
+ thisObj->createArgumentsObject(exec);
+
+ return thisObj->d()->argumentsObject;
+}
+
+PropertySlot::GetValueFunc ActivationImp::getArgumentsGetter()
+{
+ return ActivationImp::argumentsGetter;
+}
+
+bool ActivationImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (symbolTableGet(propertyName, slot))
+ return true;
+
+ if (JSValue** location = getDirectLocation(propertyName)) {
+ slot.setValueSlot(this, location);
+ return true;
+ }
+
+ // Only return the built-in arguments object if it wasn't overridden above.
+ if (propertyName == exec->propertyNames().arguments) {
+ for (ExecState* e = exec; e; e = e->callingExecState())
+ if (e->function() == d()->function) {
+ e->dynamicGlobalObject()->tearOffActivation(e, e != exec);
+ ActivationImp* newActivation = e->activationObject();
+ slot.setCustom(newActivation, newActivation->getArgumentsGetter());
+ return true;
+ }
+
+ slot.setCustom(this, getArgumentsGetter());
+ return true;
+ }
+
+ // We don't call through to JSObject because there's no way to give an
+ // activation object getter properties or a prototype.
+ ASSERT(!_prop.hasGetterSetterProperties());
+ ASSERT(prototype() == jsNull());
+ return false;
+}
+
+bool ActivationImp::deleteProperty(ExecState* exec, const Identifier& propertyName)
+{
+ if (propertyName == exec->propertyNames().arguments)
+ return false;
+
+ return JSVariableObject::deleteProperty(exec, propertyName);
+}
+
+void ActivationImp::put(ExecState*, const Identifier& propertyName, JSValue* value)
+{
+ if (symbolTablePut(propertyName, value))
+ return;
+
+ // We don't call through to JSObject because __proto__ and getter/setter
+ // properties are non-standard extensions that other implementations do not
+ // expose in the activation object.
+ ASSERT(!_prop.hasGetterSetterProperties());
+ _prop.put(propertyName, value, 0, true);
+}
+
+void ActivationImp::initializeVariable(ExecState*, const Identifier& propertyName, JSValue* value, unsigned attributes)
+{
+ if (symbolTableInitializeVariable(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(!_prop.hasGetterSetterProperties());
+ _prop.put(propertyName, value, attributes, true);
+}
+
+void ActivationImp::markChildren()
+{
+ LocalStorage& localStorage = d()->localStorage;
+ size_t size = localStorage.size();
+
+ for (size_t i = 0; i < size; ++i) {
+ JSValue* value = localStorage[i].value;
+
+ if (!value->marked())
+ value->mark();
+ }
+
+ if (!d()->function->marked())
+ d()->function->mark();
+
+ if (d()->argumentsObject && !d()->argumentsObject->marked())
+ d()->argumentsObject->mark();
+}
+
+void ActivationImp::mark()
+{
+ JSObject::mark();
+ markChildren();
+}
+
+void ActivationImp::createArgumentsObject(ExecState* exec)
+{
+ // Since "arguments" is only accessible while a function is being called,
+ // we can retrieve our argument list from the ExecState for our function
+ // call instead of storing the list ourselves.
+ d()->argumentsObject = new Arguments(exec, d()->exec->function(), *d()->exec->arguments(), this);
+}
+
+ActivationImp::ActivationData::ActivationData(const ActivationData& old)
+ : JSVariableObjectData(old)
+ , exec(old.exec)
+ , function(old.function)
+ , argumentsObject(old.argumentsObject)
+ , isOnStack(false)
+{
+}
+
+// ------------------------------ Global Functions -----------------------------------
+
+static JSValue* encode(ExecState* exec, const List& args, const char* do_not_escape)
+{
+ UString r = "", s, str = args[0]->toString(exec);
+ CString cstr = str.UTF8String(true);
+ if (!cstr.c_str())
+ return throwError(exec, URIError, "String contained an illegal UTF-16 sequence.");
+ const char* p = cstr.c_str();
+ for (size_t k = 0; k < cstr.size(); k++, p++) {
+ char c = *p;
+ if (c && strchr(do_not_escape, c)) {
+ r.append(c);
+ } else {
+ char tmp[4];
+ sprintf(tmp, "%%%02X", (unsigned char)c);
+ r += tmp;
+ }
+ }
+ return jsString(r);
+}
+
+static JSValue* decode(ExecState* exec, const List& args, const char* do_not_unescape, bool strict)
+{
+ UString s = "", str = args[0]->toString(exec);
+ int k = 0, len = str.size();
+ const UChar* d = str.data();
+ UChar u;
+ while (k < len) {
+ const UChar* p = d + k;
+ UChar c = *p;
+ if (c == '%') {
+ int charLen = 0;
+ if (k <= len - 3 && isASCIIHexDigit(p[1].uc) && isASCIIHexDigit(p[2].uc)) {
+ const char b0 = Lexer::convertHex(p[1].uc, p[2].uc);
+ const int sequenceLen = UTF8SequenceLength(b0);
+ if (sequenceLen != 0 && k <= len - sequenceLen * 3) {
+ charLen = sequenceLen * 3;
+ char sequence[5];
+ sequence[0] = b0;
+ for (int i = 1; i < sequenceLen; ++i) {
+ const UChar* q = p + i * 3;
+ if (q[0] == '%' && isASCIIHexDigit(q[1].uc) && isASCIIHexDigit(q[2].uc))
+ sequence[i] = Lexer::convertHex(q[1].uc, q[2].uc);
+ 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.
+ s.append(static_cast<unsigned short>(0xD800 | ((character - 0x10000) >> 10)));
+ u = static_cast<unsigned short>(0xDC00 | ((character - 0x10000) & 0x3FF));
+ } else {
+ u = static_cast<unsigned short>(character);
+ }
+ }
+ }
+ }
+ if (charLen == 0) {
+ if (strict)
+ return throwError(exec, URIError);
+ // The only case where we don't use "strict" mode is the "unescape" function.
+ // For that, it's good to support the wonky "%u" syntax for compatibility with WinIE.
+ if (k <= len - 6 && p[1] == 'u'
+ && isASCIIHexDigit(p[2].uc) && isASCIIHexDigit(p[3].uc)
+ && isASCIIHexDigit(p[4].uc) && isASCIIHexDigit(p[5].uc)) {
+ charLen = 6;
+ u = Lexer::convertUnicode(p[2].uc, p[3].uc, p[4].uc, p[5].uc);
+ }
+ }
+ if (charLen && (u.uc == 0 || u.uc >= 128 || !strchr(do_not_unescape, u.low()))) {
+ c = u;
+ k += charLen - 1;
+ }
+ }
+ k++;
+ s.append(c);
+ }
+ return jsString(s);
+}
+
+static bool isStrWhiteSpace(unsigned short c)
+{
+ switch (c) {
+ case 0x0009:
+ case 0x000A:
+ case 0x000B:
+ case 0x000C:
+ case 0x000D:
+ case 0x0020:
+ case 0x00A0:
+ case 0x2028:
+ case 0x2029:
+ return true;
+ default:
+ return isSeparatorSpace(c);
+ }
+}
+
+static int parseDigit(unsigned short c, int radix)
+{
+ int digit = -1;
+
+ if (c >= '0' && c <= '9') {
+ digit = c - '0';
+ } else if (c >= 'A' && c <= 'Z') {
+ digit = c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'z') {
+ digit = c - 'a' + 10;
+ }
+
+ if (digit >= radix)
+ return -1;
+ return digit;
+}
+
+double parseIntOverflow(const char* s, int length, int radix)
+{
+ double number = 0.0;
+ double radixMultiplier = 1.0;
+
+ for (const char* p = s + length - 1; p >= s; p--) {
+ if (radixMultiplier == Inf) {
+ if (*p != '0') {
+ number = Inf;
+ break;
+ }
+ } else {
+ int digit = parseDigit(*p, radix);
+ number += digit * radixMultiplier;
+ }
+
+ radixMultiplier *= radix;
+ }
+
+ return number;
+}
+
+static double parseInt(const UString& s, int radix)
+{
+ int length = s.size();
+ int p = 0;
+
+ while (p < length && isStrWhiteSpace(s[p].uc)) {
+ ++p;
+ }
+
+ double sign = 1;
+ if (p < length) {
+ if (s[p] == '+') {
+ ++p;
+ } else if (s[p] == '-') {
+ sign = -1;
+ ++p;
+ }
+ }
+
+ if ((radix == 0 || radix == 16) && length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {
+ radix = 16;
+ p += 2;
+ } else if (radix == 0) {
+ if (p < length && s[p] == '0')
+ radix = 8;
+ else
+ radix = 10;
+ }
+
+ if (radix < 2 || radix > 36)
+ return NaN;
+
+ int firstDigitPosition = p;
+ bool sawDigit = false;
+ double number = 0;
+ while (p < length) {
+ int digit = parseDigit(s[p].uc, radix);
+ if (digit == -1)
+ break;
+ sawDigit = true;
+ number *= radix;
+ number += digit;
+ ++p;
+ }
+
+ if (number >= mantissaOverflowLowerBound) {
+ if (radix == 10)
+ number = kjs_strtod(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), 0);
+ else if (radix == 2 || radix == 4 || radix == 8 || radix == 16 || radix == 32)
+ number = parseIntOverflow(s.substr(firstDigitPosition, p - firstDigitPosition).ascii(), p - firstDigitPosition, radix);
+ }
+
+ if (!sawDigit)
+ return NaN;
+
+ return sign * number;
+}
+
+static double parseFloat(const UString& s)
+{
+ // Check for 0x prefix here, because toDouble allows it, but we must treat it as 0.
+ // Need to skip any whitespace and then one + or - sign.
+ int length = s.size();
+ int p = 0;
+ while (p < length && isStrWhiteSpace(s[p].uc)) {
+ ++p;
+ }
+ if (p < length && (s[p] == '+' || s[p] == '-')) {
+ ++p;
+ }
+ if (length - p >= 2 && s[p] == '0' && (s[p + 1] == 'x' || s[p + 1] == 'X')) {
+ return 0;
+ }
+
+ return s.toDouble( true /*tolerant*/, false /* NaN for empty string */ );
+}
+
+JSValue* globalFuncEval(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ JSValue* x = args[0];
+ if (!x->isString())
+ return x;
+
+ UString s = x->toString(exec);
+
+ int sourceId;
+ int errLine;
+ UString errMsg;
+ RefPtr<EvalNode> evalNode = parser().parse<EvalNode>(UString(), 0, s.data(), s.size(), &sourceId, &errLine, &errMsg);
+
+ Debugger* dbg = exec->dynamicGlobalObject()->debugger();
+ if (dbg) {
+ bool cont = dbg->sourceParsed(exec, sourceId, UString(), s, 0, errLine, errMsg);
+ if (!cont)
+ return jsUndefined();
+ }
+
+ // No program node means a syntax occurred
+ if (!evalNode)
+ return throwError(exec, SyntaxError, errMsg, errLine, sourceId, NULL);
+
+ bool switchGlobal = thisObj && thisObj != exec->dynamicGlobalObject() && thisObj->isGlobalObject();
+
+ // enter a new execution context
+ exec->dynamicGlobalObject()->tearOffActivation(exec);
+ JSGlobalObject* globalObject = switchGlobal ? static_cast<JSGlobalObject*>(thisObj) : exec->dynamicGlobalObject();
+ EvalExecState newExec(globalObject, evalNode.get(), exec);
+
+ if (switchGlobal) {
+ newExec.pushScope(thisObj);
+ newExec.setVariableObject(static_cast<JSGlobalObject*>(thisObj));
+ }
+ JSValue* value = evalNode->execute(&newExec);
+ if (switchGlobal)
+ newExec.popScope();
+
+ if (newExec.completionType() == Throw) {
+ exec->setException(value);
+ return value;
+ }
+
+ return value ? value : jsUndefined();
+}
+
+JSValue* globalFuncParseInt(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(parseInt(args[0]->toString(exec), args[1]->toInt32(exec)));
+}
+
+JSValue* globalFuncParseFloat(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(parseFloat(args[0]->toString(exec)));
+}
+
+JSValue* globalFuncIsNaN(ExecState* exec, JSObject*, const List& args)
+{
+ return jsBoolean(isnan(args[0]->toNumber(exec)));
+}
+
+JSValue* globalFuncIsFinite(ExecState* exec, JSObject*, const List& args)
+{
+ double n = args[0]->toNumber(exec);
+ return jsBoolean(!isnan(n) && !isinf(n));
+}
+
+JSValue* globalFuncDecodeURI(ExecState* exec, JSObject*, const List& args)
+{
+ static const char do_not_unescape_when_decoding_URI[] =
+ "#$&+,/:;=?@";
+
+ return decode(exec, args, do_not_unescape_when_decoding_URI, true);
+}
+
+JSValue* globalFuncDecodeURIComponent(ExecState* exec, JSObject*, const List& args)
+{
+ return decode(exec, args, "", true);
+}
+
+JSValue* globalFuncEncodeURI(ExecState* exec, JSObject*, const List& args)
+{
+ static const char do_not_escape_when_encoding_URI[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "!#$&'()*+,-./:;=?@_~";
+
+ return encode(exec, args, do_not_escape_when_encoding_URI);
+}
+
+JSValue* globalFuncEncodeURIComponent(ExecState* exec, JSObject*, const List& args)
+{
+ static const char do_not_escape_when_encoding_URI_component[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "!'()*-._~";
+
+ return encode(exec, args, do_not_escape_when_encoding_URI_component);
+}
+
+JSValue* globalFuncEscape(ExecState* exec, JSObject*, const List& args)
+{
+ static const char do_not_escape[] =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789"
+ "*+-./@_";
+
+ UString r = "", s, str = args[0]->toString(exec);
+ const UChar* c = str.data();
+ for (int k = 0; k < str.size(); k++, c++) {
+ int u = c->uc;
+ if (u > 255) {
+ char tmp[7];
+ sprintf(tmp, "%%u%04X", u);
+ s = UString(tmp);
+ } else if (u != 0 && strchr(do_not_escape, (char)u))
+ s = UString(c, 1);
+ else {
+ char tmp[4];
+ sprintf(tmp, "%%%02X", u);
+ s = UString(tmp);
+ }
+ r += s;
+ }
+
+ return jsString(r);
+}
+
+JSValue* globalFuncUnescape(ExecState* exec, JSObject*, const List& args)
+{
+ UString s = "", str = args[0]->toString(exec);
+ int k = 0, len = str.size();
+ while (k < len) {
+ const UChar* c = str.data() + k;
+ UChar u;
+ if (*c == UChar('%') && k <= len - 6 && *(c + 1) == UChar('u')) {
+ if (Lexer::isHexDigit((c + 2)->uc) && Lexer::isHexDigit((c + 3)->uc) && Lexer::isHexDigit((c + 4)->uc) && Lexer::isHexDigit((c + 5)->uc)) {
+ u = Lexer::convertUnicode((c + 2)->uc, (c + 3)->uc, (c + 4)->uc, (c + 5)->uc);
+ c = &u;
+ k += 5;
+ }
+ } else if (*c == UChar('%') && k <= len - 3 && Lexer::isHexDigit((c + 1)->uc) && Lexer::isHexDigit((c + 2)->uc)) {
+ u = UChar(Lexer::convertHex((c+1)->uc, (c+2)->uc));
+ c = &u;
+ k += 2;
+ }
+ k++;
+ s += UString(c, 1);
+ }
+
+ return jsString(s);
+}
+
+#ifndef NDEBUG
+JSValue* globalFuncKJSPrint(ExecState* exec, JSObject*, const List& args)
+{
+ puts(args[0]->toString(exec).ascii());
+ return jsUndefined();
+}
+#endif
+
+// ------------------------------ PrototypeFunction -------------------------------
+
+PrototypeFunction::PrototypeFunction(ExecState* exec, int len, const Identifier& name, JSMemberFunction function)
+ : InternalFunctionImp(exec->lexicalGlobalObject()->functionPrototype(), name)
+ , m_function(function)
+{
+ ASSERT_ARG(function, function);
+ putDirect(exec->propertyNames().length, jsNumber(len), DontDelete | ReadOnly | DontEnum);
+}
+
+PrototypeFunction::PrototypeFunction(ExecState* exec, FunctionPrototype* functionPrototype, int len, const Identifier& name, JSMemberFunction function)
+ : InternalFunctionImp(functionPrototype, name)
+ , m_function(function)
+{
+ ASSERT_ARG(function, function);
+ putDirect(exec->propertyNames().length, jsNumber(len), DontDelete | ReadOnly | DontEnum);
+}
+
+JSValue* PrototypeFunction::callAsFunction(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ return m_function(exec, thisObj, args);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/function.h b/JavaScriptCore/kjs/function.h
new file mode 100644
index 0000000..be3e136
--- /dev/null
+++ b/JavaScriptCore/kjs/function.h
@@ -0,0 +1,161 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * 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 KJS_FUNCTION_H
+#define KJS_FUNCTION_H
+
+#include "JSVariableObject.h"
+#include "LocalStorage.h"
+#include "SymbolTable.h"
+#include "nodes.h"
+#include "object.h"
+
+namespace KJS {
+
+ class ActivationImp;
+ class FunctionBodyNode;
+ class FunctionPrototype;
+ class JSGlobalObject;
+
+ class InternalFunctionImp : public JSObject {
+ public:
+ InternalFunctionImp();
+ InternalFunctionImp(FunctionPrototype*, const Identifier&);
+
+ virtual bool implementsCall() const;
+ virtual JSValue* callAsFunction(ExecState*, JSObject* thisObjec, const List& args) = 0;
+ virtual bool implementsHasInstance() const;
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+ const Identifier& functionName() const { return m_name; }
+
+ private:
+ Identifier m_name;
+ };
+
+ class FunctionImp : public InternalFunctionImp {
+ friend class ActivationImp;
+ public:
+ FunctionImp(ExecState*, const Identifier& name, FunctionBodyNode*, const ScopeChain&);
+
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual void put(ExecState*, const Identifier& propertyName, JSValue*);
+ virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
+
+ virtual bool implementsConstruct() const { return true; }
+ virtual JSObject* construct(ExecState*, const List& args);
+
+ virtual JSValue* callAsFunction(ExecState*, JSObject* thisObj, const List& args);
+
+ // Note: unlike body->paramName, this returns Identifier::null for parameters
+ // that will never get set, due to later param having the same name
+ Identifier getParameterName(int index);
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+
+ RefPtr<FunctionBodyNode> body;
+
+ void setScope(const ScopeChain& s) { _scope = s; }
+ const ScopeChain& scope() const { return _scope; }
+
+ virtual void mark();
+
+ private:
+ ScopeChain _scope;
+
+ static JSValue* argumentsGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
+ static JSValue* callerGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
+ static JSValue* lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
+ };
+
+ class IndexToNameMap {
+ public:
+ IndexToNameMap(FunctionImp* func, const List& args);
+ ~IndexToNameMap();
+
+ Identifier& operator[](int index);
+ Identifier& operator[](const Identifier &indexIdentifier);
+ bool isMapped(const Identifier& index) const;
+ void unMap(const Identifier& index);
+
+ private:
+ IndexToNameMap(); // prevent construction w/o parameters
+ int size;
+ Identifier* _map;
+ };
+
+ class Arguments : public JSObject {
+ public:
+ Arguments(ExecState*, FunctionImp* func, const List& args, ActivationImp* act);
+ virtual void mark();
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual void put(ExecState*, const Identifier& propertyName, JSValue*);
+ virtual bool deleteProperty(ExecState*, const Identifier& propertyName);
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+ private:
+ static JSValue* mappedIndexGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot);
+
+ ActivationImp* _activationObject;
+ mutable IndexToNameMap indexToNameMap;
+ };
+
+ class PrototypeFunction : public InternalFunctionImp {
+ public:
+ typedef KJS::JSValue* (*JSMemberFunction)(ExecState*, JSObject*, const List&);
+
+ PrototypeFunction(ExecState*, int len, const Identifier&, JSMemberFunction);
+ PrototypeFunction(ExecState*, FunctionPrototype*, int len, const Identifier&, JSMemberFunction);
+
+ virtual JSValue* callAsFunction(ExecState* exec, JSObject* thisObj, const List&);
+
+ private:
+ const JSMemberFunction m_function;
+ };
+
+
+ // Global Functions
+ JSValue* globalFuncEval(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncParseInt(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncParseFloat(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncIsNaN(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncIsFinite(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncDecodeURI(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncDecodeURIComponent(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncEncodeURI(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncEncodeURIComponent(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncEscape(ExecState*, JSObject*, const List&);
+ JSValue* globalFuncUnescape(ExecState*, JSObject*, const List&);
+#ifndef NDEBUG
+ JSValue* globalFuncKJSPrint(ExecState*, JSObject*, const List&);
+#endif
+
+ static const double mantissaOverflowLowerBound = 9007199254740992.0;
+ double parseIntOverflow(const char*, int length, int radix);
+
+} // namespace
+
+#endif
diff --git a/JavaScriptCore/kjs/function_object.cpp b/JavaScriptCore/kjs/function_object.cpp
new file mode 100644
index 0000000..3c56616
--- /dev/null
+++ b/JavaScriptCore/kjs/function_object.cpp
@@ -0,0 +1,239 @@
+/*
+ * 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 "function_object.h"
+
+#include "JSGlobalObject.h"
+#include "Parser.h"
+#include "array_object.h"
+#include "debugger.h"
+#include "function.h"
+#include "internal.h"
+#include "lexer.h"
+#include "nodes.h"
+#include "object.h"
+#include <stdio.h>
+#include <string.h>
+#include <wtf/Assertions.h>
+
+namespace KJS {
+
+// ------------------------------ FunctionPrototype -------------------------
+
+static JSValue* functionProtoFuncToString(ExecState*, JSObject*, const List&);
+static JSValue* functionProtoFuncApply(ExecState*, JSObject*, const List&);
+static JSValue* functionProtoFuncCall(ExecState*, JSObject*, const List&);
+
+FunctionPrototype::FunctionPrototype(ExecState* exec)
+{
+ static const Identifier* applyPropertyName = new Identifier("apply");
+ static const Identifier* callPropertyName = new Identifier("call");
+
+ putDirect(exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
+
+ putDirectFunction(new PrototypeFunction(exec, this, 0, exec->propertyNames().toString, functionProtoFuncToString), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, this, 2, *applyPropertyName, functionProtoFuncApply), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, this, 1, *callPropertyName, functionProtoFuncCall), DontEnum);
+}
+
+// ECMA 15.3.4
+JSValue* FunctionPrototype::callAsFunction(ExecState*, JSObject*, const List&)
+{
+ return jsUndefined();
+}
+
+// Functions
+
+JSValue* functionProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj || !thisObj->inherits(&InternalFunctionImp::info)) {
+#ifndef NDEBUG
+ fprintf(stderr,"attempted toString() call on null or non-function object\n");
+#endif
+ return throwError(exec, TypeError);
+ }
+
+ if (thisObj->inherits(&FunctionImp::info)) {
+ FunctionImp* fi = static_cast<FunctionImp*>(thisObj);
+ return jsString("function " + fi->functionName().ustring() + "(" + fi->body->paramString() + ") " + fi->body->toString());
+ }
+
+ return jsString("function " + static_cast<InternalFunctionImp*>(thisObj)->functionName().ustring() + "() {\n [native code]\n}");
+}
+
+JSValue* functionProtoFuncApply(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->implementsCall())
+ return throwError(exec, TypeError);
+
+ JSValue* thisArg = args[0];
+ JSValue* argArray = args[1];
+
+ JSObject* applyThis;
+ if (thisArg->isUndefinedOrNull())
+ applyThis = exec->dynamicGlobalObject();
+ else
+ applyThis = thisArg->toObject(exec);
+
+ List applyArgs;
+ if (!argArray->isUndefinedOrNull()) {
+ if (argArray->isObject() &&
+ (static_cast<JSObject*>(argArray)->inherits(&ArrayInstance::info) ||
+ static_cast<JSObject*>(argArray)->inherits(&Arguments::info))) {
+
+ JSObject* argArrayObj = static_cast<JSObject*>(argArray);
+ unsigned int length = argArrayObj->get(exec, exec->propertyNames().length)->toUInt32(exec);
+ for (unsigned int i = 0; i < length; i++)
+ applyArgs.append(argArrayObj->get(exec, i));
+ } else
+ return throwError(exec, TypeError);
+ }
+
+ return thisObj->call(exec, applyThis, applyArgs);
+}
+
+JSValue* functionProtoFuncCall(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->implementsCall())
+ return throwError(exec, TypeError);
+
+ JSValue* thisArg = args[0];
+
+ JSObject* callThis;
+ if (thisArg->isUndefinedOrNull())
+ callThis = exec->dynamicGlobalObject();
+ else
+ callThis = thisArg->toObject(exec);
+
+ List argsTail;
+ args.getSlice(1, argsTail);
+ return thisObj->call(exec, callThis, argsTail);
+}
+
+// ------------------------------ FunctionObjectImp ----------------------------
+
+FunctionObjectImp::FunctionObjectImp(ExecState* exec, FunctionPrototype* functionPrototype)
+ : InternalFunctionImp(functionPrototype, functionPrototype->classInfo()->className)
+{
+ putDirect(exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly);
+
+ // Number of arguments for constructor
+ putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly | DontDelete | DontEnum);
+}
+
+bool FunctionObjectImp::implementsConstruct() const
+{
+ return true;
+}
+
+// ECMA 15.3.2 The Function Constructor
+JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args, const Identifier& functionName, const UString& sourceURL, int lineNumber)
+{
+ UString p("");
+ UString body;
+ int argsSize = args.size();
+ if (argsSize == 0)
+ body = "";
+ else if (argsSize == 1)
+ body = args[0]->toString(exec);
+ else {
+ p = args[0]->toString(exec);
+ for (int k = 1; k < argsSize - 1; k++)
+ p += "," + args[k]->toString(exec);
+ body = args[argsSize - 1]->toString(exec);
+ }
+
+ // parse the source code
+ int sourceId;
+ int errLine;
+ UString errMsg;
+ RefPtr<FunctionBodyNode> functionBody = parser().parse<FunctionBodyNode>(sourceURL, lineNumber, body.data(), body.size(), &sourceId, &errLine, &errMsg);
+
+ // notify debugger that source has been parsed
+ // send empty sourceURL to indicate constructed code
+ Debugger* dbg = exec->dynamicGlobalObject()->debugger();
+ if (dbg && !dbg->sourceParsed(exec, sourceId, UString(), body, lineNumber, errLine, errMsg))
+ return new JSObject();
+
+ // No program node == syntax error - throw a syntax error
+ if (!functionBody)
+ // We can't return a Completion(Throw) here, so just set the exception
+ // and return it
+ return throwError(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL);
+
+ ScopeChain scopeChain;
+ scopeChain.push(exec->lexicalGlobalObject());
+
+ FunctionImp* fimp = new FunctionImp(exec, functionName, functionBody.get(), scopeChain);
+
+ // parse parameter list. throw syntax error on illegal identifiers
+ int len = p.size();
+ const UChar* c = p.data();
+ int i = 0, params = 0;
+ UString param;
+ while (i < len) {
+ while (*c == ' ' && i < len)
+ c++, i++;
+ if (Lexer::isIdentStart(c->uc)) { // else error
+ param = UString(c, 1);
+ c++, i++;
+ while (i < len && (Lexer::isIdentPart(c->uc))) {
+ param += UString(c, 1);
+ c++, i++;
+ }
+ while (i < len && *c == ' ')
+ c++, i++;
+ if (i == len) {
+ functionBody->parameters().append(Identifier(param));
+ params++;
+ break;
+ } else if (*c == ',') {
+ functionBody->parameters().append(Identifier(param));
+ params++;
+ c++, i++;
+ continue;
+ } // else error
+ }
+ return throwError(exec, SyntaxError, "Syntax error in parameter list");
+ }
+
+ List consArgs;
+
+ JSObject* objCons = exec->lexicalGlobalObject()->objectConstructor();
+ JSObject* prototype = objCons->construct(exec, exec->emptyList());
+ prototype->putDirect(exec->propertyNames().constructor, fimp, DontEnum);
+ fimp->putDirect(exec->propertyNames().prototype, prototype, DontDelete);
+ return fimp;
+}
+
+// ECMA 15.3.2 The Function Constructor
+JSObject* FunctionObjectImp::construct(ExecState* exec, const List& args)
+{
+ return construct(exec, args, "anonymous", UString(), 0);
+}
+
+// ECMA 15.3.1 The Function Constructor Called as a Function
+JSValue* FunctionObjectImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
+{
+ return construct(exec, args);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/function_object.h b/JavaScriptCore/kjs/function_object.h
new file mode 100644
index 0000000..cd0fe3e
--- /dev/null
+++ b/JavaScriptCore/kjs/function_object.h
@@ -0,0 +1,61 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 FUNCTION_OBJECT_H_
+#define FUNCTION_OBJECT_H_
+
+#include "object_object.h"
+#include "function.h"
+
+namespace KJS {
+
+ /**
+ * @internal
+ *
+ * The initial value of Function.prototype (and thus all objects created
+ * with the Function constructor)
+ */
+ class FunctionPrototype : public InternalFunctionImp {
+ public:
+ FunctionPrototype(ExecState*);
+
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+ };
+
+ /**
+ * @internal
+ *
+ * The initial value of the the global variable's "Function" property
+ */
+ class FunctionObjectImp : public InternalFunctionImp {
+ public:
+ FunctionObjectImp(ExecState*, FunctionPrototype*);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject* construct(ExecState*, const List&);
+ virtual JSObject* construct(ExecState*, const List&, const Identifier& functionName, const UString& sourceURL, int lineNumber);
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+ };
+
+} // namespace KJS
+
+#endif // _FUNCTION_OBJECT_H_
diff --git a/JavaScriptCore/kjs/grammar.y b/JavaScriptCore/kjs/grammar.y
new file mode 100644
index 0000000..658ae89
--- /dev/null
+++ b/JavaScriptCore/kjs/grammar.y
@@ -0,0 +1,1261 @@
+%{
+
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <stdlib.h>
+#include "value.h"
+#include "object.h"
+#include "types.h"
+#include "nodes.h"
+#include "lexer.h"
+#include "internal.h"
+#include "CommonIdentifiers.h"
+#include "NodeInfo.h"
+#include "Parser.h"
+#include <wtf/MathExtras.h>
+
+// Not sure why, but yacc doesn't add this define along with the others.
+#define yylloc kjsyylloc
+
+#define YYMAXDEPTH 10000
+#define YYENABLE_NLS 0
+
+/* default values for bison */
+#define YYDEBUG 0 // Set to 1 to debug a parse error.
+#define kjsyydebug 0 // Set to 1 to debug a parse error.
+#if !PLATFORM(DARWIN)
+ // avoid triggering warnings in older bison
+#define YYERROR_VERBOSE
+#endif
+
+extern int kjsyylex();
+int kjsyyerror(const char *);
+static bool allowAutomaticSemicolon();
+
+#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon()) YYABORT; } while (0)
+#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line)
+
+using namespace KJS;
+using namespace std;
+
+static AddNode* makeAddNode(ExpressionNode*, ExpressionNode*);
+static LessNode* makeLessNode(ExpressionNode*, ExpressionNode*);
+static ExpressionNode* makeAssignNode(ExpressionNode* loc, Operator, ExpressionNode* expr);
+static ExpressionNode* makePrefixNode(ExpressionNode* expr, Operator);
+static ExpressionNode* makePostfixNode(ExpressionNode* expr, Operator);
+static PropertyNode* makeGetterOrSetterPropertyNode(const Identifier &getOrSet, const Identifier& name, ParameterNode*, FunctionBodyNode*);
+static ExpressionNode* makeFunctionCallNode(ExpressionNode* func, ArgumentsNode*);
+static ExpressionNode* makeTypeOfNode(ExpressionNode*);
+static ExpressionNode* makeDeleteNode(ExpressionNode*);
+static ExpressionNode* makeNegateNode(ExpressionNode*);
+static NumberNode* makeNumberNode(double);
+static StatementNode* makeVarStatementNode(ExpressionNode*);
+static ExpressionNode* combineVarInitializers(ExpressionNode* list, AssignResolveNode* init);
+
+
+#if COMPILER(MSVC)
+
+#pragma warning(disable: 4065)
+#pragma warning(disable: 4244)
+#pragma warning(disable: 4702)
+
+// At least some of the time, the declarations of malloc and free that bison
+// generates are causing warnings. A way to avoid this is to explicitly define
+// the macros so that bison doesn't try to declare malloc and free.
+#define YYMALLOC malloc
+#define YYFREE free
+
+#endif
+
+template <typename T> NodeInfo<T> createNodeInfo(T node, ParserRefCountedData<DeclarationStacks::VarStack>* varDecls,
+ ParserRefCountedData<DeclarationStacks::FunctionStack>* funcDecls)
+{
+ NodeInfo<T> result = {node, varDecls, funcDecls};
+ return result;
+}
+
+template <typename T> T mergeDeclarationLists(T decls1, T decls2)
+{
+ // decls1 or both are null
+ if (!decls1)
+ return decls2;
+ // only decls1 is non-null
+ if (!decls2)
+ return decls1;
+
+ // Both are non-null
+ decls1->data.append(decls2->data);
+
+ // We manually release the declaration lists to avoid accumulating many many
+ // unused heap allocated vectors
+ decls2->ref();
+ decls2->deref();
+ return decls1;
+}
+
+static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs)
+{
+ if (!varDecls)
+ varDecls = new ParserRefCountedData<DeclarationStacks::VarStack>;
+
+ varDecls->data.append(make_pair(ident, attrs));
+
+}
+
+static inline void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl)
+{
+ unsigned attrs = DeclarationStacks::IsConstant;
+ if (decl->m_init)
+ attrs |= DeclarationStacks::HasInitializer;
+ appendToVarDeclarationList(varDecls, decl->m_ident, attrs);
+}
+
+%}
+
+%union {
+ int intValue;
+ double doubleValue;
+ UString* string;
+ Identifier* ident;
+
+ // expression subtrees
+ ExpressionNode* expressionNode;
+ FuncDeclNode* funcDeclNode;
+ PropertyNode* propertyNode;
+ ArgumentsNode* argumentsNode;
+ ConstDeclNode* constDeclNode;
+ CaseBlockNodeInfo caseBlockNode;
+ CaseClauseNodeInfo caseClauseNode;
+ FuncExprNode* funcExprNode;
+
+ // statement nodes
+ StatementNodeInfo statementNode;
+ FunctionBodyNode* functionBodyNode;
+ ProgramNode* programNode;
+
+ SourceElementsInfo sourceElements;
+ PropertyList propertyList;
+ ArgumentList argumentList;
+ VarDeclListInfo varDeclList;
+ ConstDeclListInfo constDeclList;
+ ClauseListInfo clauseList;
+ ElementList elementList;
+ ParameterList parameterList;
+
+ Operator op;
+}
+
+%start Program
+
+/* literals */
+%token NULLTOKEN TRUETOKEN FALSETOKEN
+
+/* keywords */
+%token BREAK CASE DEFAULT FOR NEW VAR CONSTTOKEN CONTINUE
+%token FUNCTION RETURN VOIDTOKEN DELETETOKEN
+%token IF THISTOKEN DO WHILE INTOKEN INSTANCEOF TYPEOF
+%token SWITCH WITH RESERVED
+%token THROW TRY CATCH FINALLY
+%token DEBUGGER
+
+/* give an if without an else higher precedence than an else to resolve the ambiguity */
+%nonassoc IF_WITHOUT_ELSE
+%nonassoc ELSE
+
+/* punctuators */
+%token EQEQ NE /* == and != */
+%token STREQ STRNEQ /* === and !== */
+%token LE GE /* < and > */
+%token OR AND /* || and && */
+%token PLUSPLUS MINUSMINUS /* ++ and -- */
+%token LSHIFT /* << */
+%token RSHIFT URSHIFT /* >> and >>> */
+%token PLUSEQUAL MINUSEQUAL /* += and -= */
+%token MULTEQUAL DIVEQUAL /* *= and /= */
+%token LSHIFTEQUAL /* <<= */
+%token RSHIFTEQUAL URSHIFTEQUAL /* >>= and >>>= */
+%token ANDEQUAL MODEQUAL /* &= and %= */
+%token XOREQUAL OREQUAL /* ^= and |= */
+
+/* terminal types */
+%token <doubleValue> NUMBER
+%token <string> STRING
+%token <ident> IDENT
+
+/* automatically inserted semicolon */
+%token AUTOPLUSPLUS AUTOMINUSMINUS
+
+/* non-terminal types */
+%type <expressionNode> Literal ArrayLiteral
+
+%type <expressionNode> PrimaryExpr PrimaryExprNoBrace
+%type <expressionNode> MemberExpr MemberExprNoBF /* BF => brace or function */
+%type <expressionNode> NewExpr NewExprNoBF
+%type <expressionNode> CallExpr CallExprNoBF
+%type <expressionNode> LeftHandSideExpr LeftHandSideExprNoBF
+%type <expressionNode> PostfixExpr PostfixExprNoBF
+%type <expressionNode> UnaryExpr UnaryExprNoBF UnaryExprCommon
+%type <expressionNode> MultiplicativeExpr MultiplicativeExprNoBF
+%type <expressionNode> AdditiveExpr AdditiveExprNoBF
+%type <expressionNode> ShiftExpr ShiftExprNoBF
+%type <expressionNode> RelationalExpr RelationalExprNoIn RelationalExprNoBF
+%type <expressionNode> EqualityExpr EqualityExprNoIn EqualityExprNoBF
+%type <expressionNode> BitwiseANDExpr BitwiseANDExprNoIn BitwiseANDExprNoBF
+%type <expressionNode> BitwiseXORExpr BitwiseXORExprNoIn BitwiseXORExprNoBF
+%type <expressionNode> BitwiseORExpr BitwiseORExprNoIn BitwiseORExprNoBF
+%type <expressionNode> LogicalANDExpr LogicalANDExprNoIn LogicalANDExprNoBF
+%type <expressionNode> LogicalORExpr LogicalORExprNoIn LogicalORExprNoBF
+%type <expressionNode> ConditionalExpr ConditionalExprNoIn ConditionalExprNoBF
+%type <expressionNode> AssignmentExpr AssignmentExprNoIn AssignmentExprNoBF
+%type <expressionNode> Expr ExprNoIn ExprNoBF
+
+%type <expressionNode> ExprOpt ExprNoInOpt
+
+%type <statementNode> Statement Block
+%type <statementNode> VariableStatement ConstStatement EmptyStatement ExprStatement
+%type <statementNode> IfStatement IterationStatement ContinueStatement
+%type <statementNode> BreakStatement ReturnStatement WithStatement
+%type <statementNode> SwitchStatement LabelledStatement
+%type <statementNode> ThrowStatement TryStatement
+%type <statementNode> DebuggerStatement
+%type <statementNode> SourceElement
+
+%type <expressionNode> Initializer InitializerNoIn
+%type <funcDeclNode> FunctionDeclaration
+%type <funcExprNode> FunctionExpr
+%type <functionBodyNode> FunctionBody
+%type <sourceElements> SourceElements
+%type <parameterList> FormalParameterList
+%type <op> AssignmentOperator
+%type <argumentsNode> Arguments
+%type <argumentList> ArgumentList
+%type <varDeclList> VariableDeclarationList VariableDeclarationListNoIn
+%type <constDeclList> ConstDeclarationList
+%type <constDeclNode> ConstDeclaration
+%type <caseBlockNode> CaseBlock
+%type <caseClauseNode> CaseClause DefaultClause
+%type <clauseList> CaseClauses CaseClausesOpt
+%type <intValue> Elision ElisionOpt
+%type <elementList> ElementList
+%type <propertyNode> Property
+%type <propertyList> PropertyList
+%%
+
+Literal:
+ NULLTOKEN { $$ = new NullNode; }
+ | TRUETOKEN { $$ = new TrueNode; }
+ | FALSETOKEN { $$ = new FalseNode; }
+ | NUMBER { $$ = makeNumberNode($1); }
+ | STRING { $$ = new StringNode($1); }
+ | '/' /* regexp */ {
+ Lexer& l = lexer();
+ if (!l.scanRegExp())
+ YYABORT;
+ $$ = new RegExpNode(l.pattern(), l.flags());
+ }
+ | DIVEQUAL /* regexp with /= */ {
+ Lexer& l = lexer();
+ if (!l.scanRegExp())
+ YYABORT;
+ $$ = new RegExpNode("=" + l.pattern(), l.flags());
+ }
+;
+
+Property:
+ IDENT ':' AssignmentExpr { $$ = new PropertyNode(*$1, $3, PropertyNode::Constant); }
+ | STRING ':' AssignmentExpr { $$ = new PropertyNode(Identifier(*$1), $3, PropertyNode::Constant); }
+ | NUMBER ':' AssignmentExpr { $$ = new PropertyNode(Identifier(UString::from($1)), $3, PropertyNode::Constant); }
+ | IDENT IDENT '(' ')' '{' FunctionBody '}' { $$ = makeGetterOrSetterPropertyNode(*$1, *$2, 0, $6); DBG($6, @5, @7); if (!$$) YYABORT; }
+ | IDENT IDENT '(' FormalParameterList ')' '{' FunctionBody '}'
+ { $$ = makeGetterOrSetterPropertyNode(*$1, *$2, $4.head, $7); DBG($7, @6, @8); if (!$$) YYABORT; }
+;
+
+PropertyList:
+ Property { $$.head = new PropertyListNode($1);
+ $$.tail = $$.head; }
+ | PropertyList ',' Property { $$.head = $1.head;
+ $$.tail = new PropertyListNode($3, $1.tail); }
+;
+
+PrimaryExpr:
+ PrimaryExprNoBrace
+ | '{' '}' { $$ = new ObjectLiteralNode(); }
+ | '{' PropertyList '}' { $$ = new ObjectLiteralNode($2.head); }
+ /* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */
+ | '{' PropertyList ',' '}' { $$ = new ObjectLiteralNode($2.head); }
+;
+
+PrimaryExprNoBrace:
+ THISTOKEN { $$ = new ThisNode(); }
+ | Literal
+ | ArrayLiteral
+ | IDENT { $$ = new ResolveNode(*$1); }
+ | '(' Expr ')' { $$ = $2; }
+;
+
+ArrayLiteral:
+ '[' ElisionOpt ']' { $$ = new ArrayNode($2); }
+ | '[' ElementList ']' { $$ = new ArrayNode($2.head); }
+ | '[' ElementList ',' ElisionOpt ']' { $$ = new ArrayNode($4, $2.head); }
+;
+
+ElementList:
+ ElisionOpt AssignmentExpr { $$.head = new ElementNode($1, $2);
+ $$.tail = $$.head; }
+ | ElementList ',' ElisionOpt AssignmentExpr
+ { $$.head = $1.head;
+ $$.tail = new ElementNode($1.tail, $3, $4); }
+;
+
+ElisionOpt:
+ /* nothing */ { $$ = 0; }
+ | Elision
+;
+
+Elision:
+ ',' { $$ = 1; }
+ | Elision ',' { $$ = $1 + 1; }
+;
+
+MemberExpr:
+ PrimaryExpr
+ | FunctionExpr { $$ = $1; }
+ | MemberExpr '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
+ | MemberExpr '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
+ | NEW MemberExpr Arguments { $$ = new NewExprNode($2, $3); }
+;
+
+MemberExprNoBF:
+ PrimaryExprNoBrace
+ | MemberExprNoBF '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
+ | MemberExprNoBF '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
+ | NEW MemberExpr Arguments { $$ = new NewExprNode($2, $3); }
+;
+
+NewExpr:
+ MemberExpr
+ | NEW NewExpr { $$ = new NewExprNode($2); }
+;
+
+NewExprNoBF:
+ MemberExprNoBF
+ | NEW NewExpr { $$ = new NewExprNode($2); }
+;
+
+CallExpr:
+ MemberExpr Arguments { $$ = makeFunctionCallNode($1, $2); }
+ | CallExpr Arguments { $$ = makeFunctionCallNode($1, $2); }
+ | CallExpr '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
+ | CallExpr '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
+;
+
+CallExprNoBF:
+ MemberExprNoBF Arguments { $$ = makeFunctionCallNode($1, $2); }
+ | CallExprNoBF Arguments { $$ = makeFunctionCallNode($1, $2); }
+ | CallExprNoBF '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
+ | CallExprNoBF '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
+;
+
+Arguments:
+ '(' ')' { $$ = new ArgumentsNode(); }
+ | '(' ArgumentList ')' { $$ = new ArgumentsNode($2.head); }
+;
+
+ArgumentList:
+ AssignmentExpr { $$.head = new ArgumentListNode($1);
+ $$.tail = $$.head; }
+ | ArgumentList ',' AssignmentExpr { $$.head = $1.head;
+ $$.tail = new ArgumentListNode($1.tail, $3); }
+;
+
+LeftHandSideExpr:
+ NewExpr
+ | CallExpr
+;
+
+LeftHandSideExprNoBF:
+ NewExprNoBF
+ | CallExprNoBF
+;
+
+PostfixExpr:
+ LeftHandSideExpr
+ | LeftHandSideExpr PLUSPLUS { $$ = makePostfixNode($1, OpPlusPlus); }
+ | LeftHandSideExpr MINUSMINUS { $$ = makePostfixNode($1, OpMinusMinus); }
+;
+
+PostfixExprNoBF:
+ LeftHandSideExprNoBF
+ | LeftHandSideExprNoBF PLUSPLUS { $$ = makePostfixNode($1, OpPlusPlus); }
+ | LeftHandSideExprNoBF MINUSMINUS { $$ = makePostfixNode($1, OpMinusMinus); }
+;
+
+UnaryExprCommon:
+ DELETETOKEN UnaryExpr { $$ = makeDeleteNode($2); }
+ | VOIDTOKEN UnaryExpr { $$ = new VoidNode($2); }
+ | TYPEOF UnaryExpr { $$ = makeTypeOfNode($2); }
+ | PLUSPLUS UnaryExpr { $$ = makePrefixNode($2, OpPlusPlus); }
+ | AUTOPLUSPLUS UnaryExpr { $$ = makePrefixNode($2, OpPlusPlus); }
+ | MINUSMINUS UnaryExpr { $$ = makePrefixNode($2, OpMinusMinus); }
+ | AUTOMINUSMINUS UnaryExpr { $$ = makePrefixNode($2, OpMinusMinus); }
+ | '+' UnaryExpr { $$ = new UnaryPlusNode($2); }
+ | '-' UnaryExpr { $$ = makeNegateNode($2); }
+ | '~' UnaryExpr { $$ = new BitwiseNotNode($2); }
+ | '!' UnaryExpr { $$ = new LogicalNotNode($2); }
+
+UnaryExpr:
+ PostfixExpr
+ | UnaryExprCommon
+;
+
+UnaryExprNoBF:
+ PostfixExprNoBF
+ | UnaryExprCommon
+;
+
+MultiplicativeExpr:
+ UnaryExpr
+ | MultiplicativeExpr '*' UnaryExpr { $$ = new MultNode($1, $3); }
+ | MultiplicativeExpr '/' UnaryExpr { $$ = new DivNode($1, $3); }
+ | MultiplicativeExpr '%' UnaryExpr { $$ = new ModNode($1, $3); }
+;
+
+MultiplicativeExprNoBF:
+ UnaryExprNoBF
+ | MultiplicativeExprNoBF '*' UnaryExpr
+ { $$ = new MultNode($1, $3); }
+ | MultiplicativeExprNoBF '/' UnaryExpr
+ { $$ = new DivNode($1, $3); }
+ | MultiplicativeExprNoBF '%' UnaryExpr
+ { $$ = new ModNode($1, $3); }
+;
+
+AdditiveExpr:
+ MultiplicativeExpr
+ | AdditiveExpr '+' MultiplicativeExpr { $$ = makeAddNode($1, $3); }
+ | AdditiveExpr '-' MultiplicativeExpr { $$ = new SubNode($1, $3); }
+;
+
+AdditiveExprNoBF:
+ MultiplicativeExprNoBF
+ | AdditiveExprNoBF '+' MultiplicativeExpr
+ { $$ = makeAddNode($1, $3); }
+ | AdditiveExprNoBF '-' MultiplicativeExpr
+ { $$ = new SubNode($1, $3); }
+;
+
+ShiftExpr:
+ AdditiveExpr
+ | ShiftExpr LSHIFT AdditiveExpr { $$ = new LeftShiftNode($1, $3); }
+ | ShiftExpr RSHIFT AdditiveExpr { $$ = new RightShiftNode($1, $3); }
+ | ShiftExpr URSHIFT AdditiveExpr { $$ = new UnsignedRightShiftNode($1, $3); }
+;
+
+ShiftExprNoBF:
+ AdditiveExprNoBF
+ | ShiftExprNoBF LSHIFT AdditiveExpr { $$ = new LeftShiftNode($1, $3); }
+ | ShiftExprNoBF RSHIFT AdditiveExpr { $$ = new RightShiftNode($1, $3); }
+ | ShiftExprNoBF URSHIFT AdditiveExpr { $$ = new UnsignedRightShiftNode($1, $3); }
+;
+
+RelationalExpr:
+ ShiftExpr
+ | RelationalExpr '<' ShiftExpr { $$ = makeLessNode($1, $3); }
+ | RelationalExpr '>' ShiftExpr { $$ = new GreaterNode($1, $3); }
+ | RelationalExpr LE ShiftExpr { $$ = new LessEqNode($1, $3); }
+ | RelationalExpr GE ShiftExpr { $$ = new GreaterEqNode($1, $3); }
+ | RelationalExpr INSTANCEOF ShiftExpr { $$ = new InstanceOfNode($1, $3); }
+ | RelationalExpr INTOKEN ShiftExpr { $$ = new InNode($1, $3); }
+;
+
+RelationalExprNoIn:
+ ShiftExpr
+ | RelationalExprNoIn '<' ShiftExpr { $$ = makeLessNode($1, $3); }
+ | RelationalExprNoIn '>' ShiftExpr { $$ = new GreaterNode($1, $3); }
+ | RelationalExprNoIn LE ShiftExpr { $$ = new LessEqNode($1, $3); }
+ | RelationalExprNoIn GE ShiftExpr { $$ = new GreaterEqNode($1, $3); }
+ | RelationalExprNoIn INSTANCEOF ShiftExpr
+ { $$ = new InstanceOfNode($1, $3); }
+;
+
+RelationalExprNoBF:
+ ShiftExprNoBF
+ | RelationalExprNoBF '<' ShiftExpr { $$ = makeLessNode($1, $3); }
+ | RelationalExprNoBF '>' ShiftExpr { $$ = new GreaterNode($1, $3); }
+ | RelationalExprNoBF LE ShiftExpr { $$ = new LessEqNode($1, $3); }
+ | RelationalExprNoBF GE ShiftExpr { $$ = new GreaterEqNode($1, $3); }
+ | RelationalExprNoBF INSTANCEOF ShiftExpr
+ { $$ = new InstanceOfNode($1, $3); }
+ | RelationalExprNoBF INTOKEN ShiftExpr { $$ = new InNode($1, $3); }
+;
+
+EqualityExpr:
+ RelationalExpr
+ | EqualityExpr EQEQ RelationalExpr { $$ = new EqualNode($1, $3); }
+ | EqualityExpr NE RelationalExpr { $$ = new NotEqualNode($1, $3); }
+ | EqualityExpr STREQ RelationalExpr { $$ = new StrictEqualNode($1, $3); }
+ | EqualityExpr STRNEQ RelationalExpr { $$ = new NotStrictEqualNode($1, $3); }
+;
+
+EqualityExprNoIn:
+ RelationalExprNoIn
+ | EqualityExprNoIn EQEQ RelationalExprNoIn
+ { $$ = new EqualNode($1, $3); }
+ | EqualityExprNoIn NE RelationalExprNoIn
+ { $$ = new NotEqualNode($1, $3); }
+ | EqualityExprNoIn STREQ RelationalExprNoIn
+ { $$ = new StrictEqualNode($1, $3); }
+ | EqualityExprNoIn STRNEQ RelationalExprNoIn
+ { $$ = new NotStrictEqualNode($1, $3); }
+;
+
+EqualityExprNoBF:
+ RelationalExprNoBF
+ | EqualityExprNoBF EQEQ RelationalExpr
+ { $$ = new EqualNode($1, $3); }
+ | EqualityExprNoBF NE RelationalExpr { $$ = new NotEqualNode($1, $3); }
+ | EqualityExprNoBF STREQ RelationalExpr
+ { $$ = new StrictEqualNode($1, $3); }
+ | EqualityExprNoBF STRNEQ RelationalExpr
+ { $$ = new NotStrictEqualNode($1, $3); }
+;
+
+BitwiseANDExpr:
+ EqualityExpr
+ | BitwiseANDExpr '&' EqualityExpr { $$ = new BitAndNode($1, $3); }
+;
+
+BitwiseANDExprNoIn:
+ EqualityExprNoIn
+ | BitwiseANDExprNoIn '&' EqualityExprNoIn
+ { $$ = new BitAndNode($1, $3); }
+;
+
+BitwiseANDExprNoBF:
+ EqualityExprNoBF
+ | BitwiseANDExprNoBF '&' EqualityExpr { $$ = new BitAndNode($1, $3); }
+;
+
+BitwiseXORExpr:
+ BitwiseANDExpr
+ | BitwiseXORExpr '^' BitwiseANDExpr { $$ = new BitXOrNode($1, $3); }
+;
+
+BitwiseXORExprNoIn:
+ BitwiseANDExprNoIn
+ | BitwiseXORExprNoIn '^' BitwiseANDExprNoIn
+ { $$ = new BitXOrNode($1, $3); }
+;
+
+BitwiseXORExprNoBF:
+ BitwiseANDExprNoBF
+ | BitwiseXORExprNoBF '^' BitwiseANDExpr
+ { $$ = new BitXOrNode($1, $3); }
+;
+
+BitwiseORExpr:
+ BitwiseXORExpr
+ | BitwiseORExpr '|' BitwiseXORExpr { $$ = new BitOrNode($1, $3); }
+;
+
+BitwiseORExprNoIn:
+ BitwiseXORExprNoIn
+ | BitwiseORExprNoIn '|' BitwiseXORExprNoIn
+ { $$ = new BitOrNode($1, $3); }
+;
+
+BitwiseORExprNoBF:
+ BitwiseXORExprNoBF
+ | BitwiseORExprNoBF '|' BitwiseXORExpr
+ { $$ = new BitOrNode($1, $3); }
+;
+
+LogicalANDExpr:
+ BitwiseORExpr
+ | LogicalANDExpr AND BitwiseORExpr { $$ = new LogicalAndNode($1, $3); }
+;
+
+LogicalANDExprNoIn:
+ BitwiseORExprNoIn
+ | LogicalANDExprNoIn AND BitwiseORExprNoIn
+ { $$ = new LogicalAndNode($1, $3); }
+;
+
+LogicalANDExprNoBF:
+ BitwiseORExprNoBF
+ | LogicalANDExprNoBF AND BitwiseORExpr
+ { $$ = new LogicalAndNode($1, $3); }
+;
+
+LogicalORExpr:
+ LogicalANDExpr
+ | LogicalORExpr OR LogicalANDExpr { $$ = new LogicalOrNode($1, $3); }
+;
+
+LogicalORExprNoIn:
+ LogicalANDExprNoIn
+ | LogicalORExprNoIn OR LogicalANDExprNoIn
+ { $$ = new LogicalOrNode($1, $3); }
+;
+
+LogicalORExprNoBF:
+ LogicalANDExprNoBF
+ | LogicalORExprNoBF OR LogicalANDExpr { $$ = new LogicalOrNode($1, $3); }
+;
+
+ConditionalExpr:
+ LogicalORExpr
+ | LogicalORExpr '?' AssignmentExpr ':' AssignmentExpr
+ { $$ = new ConditionalNode($1, $3, $5); }
+;
+
+ConditionalExprNoIn:
+ LogicalORExprNoIn
+ | LogicalORExprNoIn '?' AssignmentExprNoIn ':' AssignmentExprNoIn
+ { $$ = new ConditionalNode($1, $3, $5); }
+;
+
+ConditionalExprNoBF:
+ LogicalORExprNoBF
+ | LogicalORExprNoBF '?' AssignmentExpr ':' AssignmentExpr
+ { $$ = new ConditionalNode($1, $3, $5); }
+;
+
+AssignmentExpr:
+ ConditionalExpr
+ | LeftHandSideExpr AssignmentOperator AssignmentExpr
+ { $$ = makeAssignNode($1, $2, $3); }
+;
+
+AssignmentExprNoIn:
+ ConditionalExprNoIn
+ | LeftHandSideExpr AssignmentOperator AssignmentExprNoIn
+ { $$ = makeAssignNode($1, $2, $3); }
+;
+
+AssignmentExprNoBF:
+ ConditionalExprNoBF
+ | LeftHandSideExprNoBF AssignmentOperator AssignmentExpr
+ { $$ = makeAssignNode($1, $2, $3); }
+;
+
+AssignmentOperator:
+ '=' { $$ = OpEqual; }
+ | PLUSEQUAL { $$ = OpPlusEq; }
+ | MINUSEQUAL { $$ = OpMinusEq; }
+ | MULTEQUAL { $$ = OpMultEq; }
+ | DIVEQUAL { $$ = OpDivEq; }
+ | LSHIFTEQUAL { $$ = OpLShift; }
+ | RSHIFTEQUAL { $$ = OpRShift; }
+ | URSHIFTEQUAL { $$ = OpURShift; }
+ | ANDEQUAL { $$ = OpAndEq; }
+ | XOREQUAL { $$ = OpXOrEq; }
+ | OREQUAL { $$ = OpOrEq; }
+ | MODEQUAL { $$ = OpModEq; }
+;
+
+Expr:
+ AssignmentExpr
+ | Expr ',' AssignmentExpr { $$ = new CommaNode($1, $3); }
+;
+
+ExprNoIn:
+ AssignmentExprNoIn
+ | ExprNoIn ',' AssignmentExprNoIn { $$ = new CommaNode($1, $3); }
+;
+
+ExprNoBF:
+ AssignmentExprNoBF
+ | ExprNoBF ',' AssignmentExpr { $$ = new CommaNode($1, $3); }
+;
+
+Statement:
+ Block
+ | VariableStatement
+ | ConstStatement
+ | EmptyStatement
+ | ExprStatement
+ | IfStatement
+ | IterationStatement
+ | ContinueStatement
+ | BreakStatement
+ | ReturnStatement
+ | WithStatement
+ | SwitchStatement
+ | LabelledStatement
+ | ThrowStatement
+ | TryStatement
+ | DebuggerStatement
+;
+
+Block:
+ '{' '}' { $$ = createNodeInfo<StatementNode*>(new BlockNode(0), 0, 0);
+ DBG($$.m_node, @1, @2); }
+ | '{' SourceElements '}' { $$ = createNodeInfo<StatementNode*>(new BlockNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
+ DBG($$.m_node, @1, @3); }
+;
+
+VariableStatement:
+ VAR VariableDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(makeVarStatementNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
+ DBG($$.m_node, @1, @3); }
+ | VAR VariableDeclarationList error { $$ = createNodeInfo<StatementNode*>(makeVarStatementNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
+ DBG($$.m_node, @1, @2);
+ AUTO_SEMICOLON; }
+;
+
+VariableDeclarationList:
+ IDENT { $$.m_node = 0;
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+ appendToVarDeclarationList($$.m_varDeclarations, *$1, 0);
+ $$.m_funcDeclarations = 0;
+ }
+ | IDENT Initializer { $$.m_node = new AssignResolveNode(*$1, $2);
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+ appendToVarDeclarationList($$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
+ $$.m_funcDeclarations = 0;
+ }
+ | VariableDeclarationList ',' IDENT
+ { $$.m_node = $1.m_node;
+ $$.m_varDeclarations = $1.m_varDeclarations;
+ appendToVarDeclarationList($$.m_varDeclarations, *$3, 0);
+ $$.m_funcDeclarations = 0;
+ }
+ | VariableDeclarationList ',' IDENT Initializer
+ { $$.m_node = combineVarInitializers($1.m_node, new AssignResolveNode(*$3, $4));
+ $$.m_varDeclarations = $1.m_varDeclarations;
+ appendToVarDeclarationList($$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
+ $$.m_funcDeclarations = 0;
+ }
+;
+
+VariableDeclarationListNoIn:
+ IDENT { $$.m_node = 0;
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+ appendToVarDeclarationList($$.m_varDeclarations, *$1, 0);
+ $$.m_funcDeclarations = 0;
+ }
+ | IDENT InitializerNoIn { $$.m_node = new AssignResolveNode(*$1, $2);
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+ appendToVarDeclarationList($$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
+ $$.m_funcDeclarations = 0;
+ }
+ | VariableDeclarationListNoIn ',' IDENT
+ { $$.m_node = $1.m_node;
+ $$.m_varDeclarations = $1.m_varDeclarations;
+ appendToVarDeclarationList($$.m_varDeclarations, *$3, 0);
+ $$.m_funcDeclarations = 0;
+ }
+ | VariableDeclarationListNoIn ',' IDENT InitializerNoIn
+ { $$.m_node = combineVarInitializers($1.m_node, new AssignResolveNode(*$3, $4));
+ $$.m_varDeclarations = $1.m_varDeclarations;
+ appendToVarDeclarationList($$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
+ $$.m_funcDeclarations = 0;
+ }
+;
+
+ConstStatement:
+ CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(new ConstStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+ DBG($$.m_node, @1, @3); }
+ | CONSTTOKEN ConstDeclarationList error
+ { $$ = createNodeInfo<StatementNode*>(new ConstStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+ DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
+;
+
+ConstDeclarationList:
+ ConstDeclaration { $$.m_node.head = $1;
+ $$.m_node.tail = $$.m_node.head;
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
+ appendToVarDeclarationList($$.m_varDeclarations, $1);
+ $$.m_funcDeclarations = 0; }
+ | ConstDeclarationList ',' ConstDeclaration
+ { $$.m_node.head = $1.m_node.head;
+ $1.m_node.tail->m_next = $3;
+ $$.m_node.tail = $3;
+ $$.m_varDeclarations = $1.m_varDeclarations;
+ appendToVarDeclarationList($$.m_varDeclarations, $3);
+ $$.m_funcDeclarations = 0; }
+;
+
+ConstDeclaration:
+ IDENT { $$ = new ConstDeclNode(*$1, 0); }
+ | IDENT Initializer { $$ = new ConstDeclNode(*$1, $2); }
+;
+
+Initializer:
+ '=' AssignmentExpr { $$ = $2; }
+;
+
+InitializerNoIn:
+ '=' AssignmentExprNoIn { $$ = $2; }
+;
+
+EmptyStatement:
+ ';' { $$ = createNodeInfo<StatementNode*>(new EmptyStatementNode(), 0, 0); }
+;
+
+ExprStatement:
+ ExprNoBF ';' { $$ = createNodeInfo<StatementNode*>(new ExprStatementNode($1), 0, 0);
+ DBG($$.m_node, @1, @2); }
+ | ExprNoBF error { $$ = createNodeInfo<StatementNode*>(new ExprStatementNode($1), 0, 0);
+ DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+;
+
+IfStatement:
+ IF '(' Expr ')' Statement %prec IF_WITHOUT_ELSE
+ { $$ = createNodeInfo<StatementNode*>(new IfNode($3, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations);
+ DBG($$.m_node, @1, @4); }
+ | IF '(' Expr ')' Statement ELSE Statement
+ { $$ = createNodeInfo<StatementNode*>(new IfElseNode($3, $5.m_node, $7.m_node), mergeDeclarationLists($5.m_varDeclarations, $7.m_varDeclarations), mergeDeclarationLists($5.m_funcDeclarations, $7.m_funcDeclarations));
+ DBG($$.m_node, @1, @4); }
+;
+
+IterationStatement:
+ DO Statement WHILE '(' Expr ')' ';' { $$ = createNodeInfo<StatementNode*>(new DoWhileNode($2.m_node, $5), $2.m_varDeclarations, $2.m_funcDeclarations);
+ DBG($$.m_node, @1, @3); }
+ | DO Statement WHILE '(' Expr ')' error { $$ = createNodeInfo<StatementNode*>(new DoWhileNode($2.m_node, $5), $2.m_varDeclarations, $2.m_funcDeclarations);
+ DBG($$.m_node, @1, @3); } // Always performs automatic semicolon insertion.
+ | WHILE '(' Expr ')' Statement { $$ = createNodeInfo<StatementNode*>(new WhileNode($3, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations);
+ DBG($$.m_node, @1, @4); }
+ | FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement
+ { $$ = createNodeInfo<StatementNode*>(new ForNode($3, $5, $7, $9.m_node, false), $9.m_varDeclarations, $9.m_funcDeclarations);
+ DBG($$.m_node, @1, @8);
+ }
+ | FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement
+ { $$ = createNodeInfo<StatementNode*>(new ForNode($4.m_node, $6, $8, $10.m_node, true),
+ mergeDeclarationLists($4.m_varDeclarations, $10.m_varDeclarations),
+ mergeDeclarationLists($4.m_funcDeclarations, $10.m_funcDeclarations));
+ DBG($$.m_node, @1, @9); }
+ | FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement
+ {
+ ExpressionNode* n = $3;
+ if (!n->isLocation())
+ YYABORT;
+ $$ = createNodeInfo<StatementNode*>(new ForInNode(n, $5, $7.m_node), $7.m_varDeclarations, $7.m_funcDeclarations);
+ DBG($$.m_node, @1, @6);
+ }
+ | FOR '(' VAR IDENT INTOKEN Expr ')' Statement
+ { ForInNode *forIn = new ForInNode(*$4, 0, $6, $8.m_node);
+ appendToVarDeclarationList($8.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
+ $$ = createNodeInfo<StatementNode*>(forIn, $8.m_varDeclarations, $8.m_funcDeclarations);
+ DBG($$.m_node, @1, @7); }
+ | FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement
+ { ForInNode *forIn = new ForInNode(*$4, $5, $7, $9.m_node);
+ appendToVarDeclarationList($9.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
+ $$ = createNodeInfo<StatementNode*>(forIn, $9.m_varDeclarations, $9.m_funcDeclarations);
+ DBG($$.m_node, @1, @8); }
+;
+
+ExprOpt:
+ /* nothing */ { $$ = 0; }
+ | Expr
+;
+
+ExprNoInOpt:
+ /* nothing */ { $$ = 0; }
+ | ExprNoIn
+;
+
+ContinueStatement:
+ CONTINUE ';' { $$ = createNodeInfo<StatementNode*>(new ContinueNode(), 0, 0);
+ DBG($$.m_node, @1, @2); }
+ | CONTINUE error { $$ = createNodeInfo<StatementNode*>(new ContinueNode(), 0, 0);
+ DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+ | CONTINUE IDENT ';' { $$ = createNodeInfo<StatementNode*>(new ContinueNode(*$2), 0, 0);
+ DBG($$.m_node, @1, @3); }
+ | CONTINUE IDENT error { $$ = createNodeInfo<StatementNode*>(new ContinueNode(*$2), 0, 0);
+ DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
+;
+
+BreakStatement:
+ BREAK ';' { $$ = createNodeInfo<StatementNode*>(new BreakNode(), 0, 0); DBG($$.m_node, @1, @2); }
+ | BREAK error { $$ = createNodeInfo<StatementNode*>(new BreakNode(), 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+ | BREAK IDENT ';' { $$ = createNodeInfo<StatementNode*>(new BreakNode(*$2), 0, 0); DBG($$.m_node, @1, @3); }
+ | BREAK IDENT error { $$ = createNodeInfo<StatementNode*>(new BreakNode(*$2), 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
+;
+
+ReturnStatement:
+ RETURN ';' { $$ = createNodeInfo<StatementNode*>(new ReturnNode(0), 0, 0); DBG($$.m_node, @1, @2); }
+ | RETURN error { $$ = createNodeInfo<StatementNode*>(new ReturnNode(0), 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+ | RETURN Expr ';' { $$ = createNodeInfo<StatementNode*>(new ReturnNode($2), 0, 0); DBG($$.m_node, @1, @3); }
+ | RETURN Expr error { $$ = createNodeInfo<StatementNode*>(new ReturnNode($2), 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
+;
+
+WithStatement:
+ WITH '(' Expr ')' Statement { $$ = createNodeInfo<StatementNode*>(new WithNode($3, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations);
+ DBG($$.m_node, @1, @4); }
+;
+
+SwitchStatement:
+ SWITCH '(' Expr ')' CaseBlock { $$ = createNodeInfo<StatementNode*>(new SwitchNode($3, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations);
+ DBG($$.m_node, @1, @4); }
+;
+
+CaseBlock:
+ '{' CaseClausesOpt '}' { $$ = createNodeInfo<CaseBlockNode*>(new CaseBlockNode($2.m_node.head, 0, 0), $2.m_varDeclarations, $2.m_funcDeclarations); }
+ | '{' CaseClausesOpt DefaultClause CaseClausesOpt '}'
+ { $$ = createNodeInfo<CaseBlockNode*>(new CaseBlockNode($2.m_node.head, $3.m_node, $4.m_node.head),
+ mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $3.m_varDeclarations), $4.m_varDeclarations),
+ mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $3.m_funcDeclarations), $4.m_funcDeclarations)); }
+;
+
+CaseClausesOpt:
+ /* nothing */ { $$.m_node.head = 0; $$.m_node.tail = 0; $$.m_varDeclarations = 0; $$.m_funcDeclarations = 0; }
+ | CaseClauses
+;
+
+CaseClauses:
+ CaseClause { $$.m_node.head = new ClauseListNode($1.m_node);
+ $$.m_node.tail = $$.m_node.head;
+ $$.m_varDeclarations = $1.m_varDeclarations;
+ $$.m_funcDeclarations = $1.m_funcDeclarations; }
+ | CaseClauses CaseClause { $$.m_node.head = $1.m_node.head;
+ $$.m_node.tail = new ClauseListNode($1.m_node.tail, $2.m_node);
+ $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations);
+ $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations);
+ }
+;
+
+CaseClause:
+ CASE Expr ':' { $$ = createNodeInfo<CaseClauseNode*>(new CaseClauseNode($2), 0, 0); }
+ | CASE Expr ':' SourceElements { $$ = createNodeInfo<CaseClauseNode*>(new CaseClauseNode($2, $4.m_node), $4.m_varDeclarations, $4.m_funcDeclarations); }
+;
+
+DefaultClause:
+ DEFAULT ':' { $$ = createNodeInfo<CaseClauseNode*>(new CaseClauseNode(0), 0, 0); }
+ | DEFAULT ':' SourceElements { $$ = createNodeInfo<CaseClauseNode*>(new CaseClauseNode(0, $3.m_node), $3.m_varDeclarations, $3.m_funcDeclarations); }
+;
+
+LabelledStatement:
+ IDENT ':' Statement { $3.m_node->pushLabel(*$1);
+ $$ = createNodeInfo<StatementNode*>(new LabelNode(*$1, $3.m_node), $3.m_varDeclarations, $3.m_funcDeclarations); }
+;
+
+ThrowStatement:
+ THROW Expr ';' { $$ = createNodeInfo<StatementNode*>(new ThrowNode($2), 0, 0); DBG($$.m_node, @1, @3); }
+ | THROW Expr error { $$ = createNodeInfo<StatementNode*>(new ThrowNode($2), 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
+;
+
+TryStatement:
+ TRY Block FINALLY Block { $$ = createNodeInfo<StatementNode*>(new TryNode($2.m_node, CommonIdentifiers::shared()->nullIdentifier, 0, $4.m_node),
+ mergeDeclarationLists($2.m_varDeclarations, $4.m_varDeclarations),
+ mergeDeclarationLists($2.m_funcDeclarations, $4.m_funcDeclarations));
+ DBG($$.m_node, @1, @2); }
+ | TRY Block CATCH '(' IDENT ')' Block { $$ = createNodeInfo<StatementNode*>(new TryNode($2.m_node, *$5, $7.m_node, 0),
+ mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations),
+ mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations));
+ DBG($$.m_node, @1, @2); }
+ | TRY Block CATCH '(' IDENT ')' Block FINALLY Block
+ { $$ = createNodeInfo<StatementNode*>(new TryNode($2.m_node, *$5, $7.m_node, $9.m_node),
+ mergeDeclarationLists(mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations), $9.m_varDeclarations),
+ mergeDeclarationLists(mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations), $9.m_funcDeclarations));
+ DBG($$.m_node, @1, @2); }
+;
+
+DebuggerStatement:
+ DEBUGGER ';' { $$ = createNodeInfo<StatementNode*>(new EmptyStatementNode(), 0, 0);
+ DBG($$.m_node, @1, @2); }
+ | DEBUGGER error { $$ = createNodeInfo<StatementNode*>(new EmptyStatementNode(), 0, 0);
+ DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+;
+
+FunctionDeclaration:
+ FUNCTION IDENT '(' ')' '{' FunctionBody '}' { $$ = new FuncDeclNode(*$2, $6); DBG($6, @5, @7); }
+ | FUNCTION IDENT '(' FormalParameterList ')' '{' FunctionBody '}'
+ { $$ = new FuncDeclNode(*$2, $4.head, $7); DBG($7, @6, @8); }
+;
+
+FunctionExpr:
+ FUNCTION '(' ')' '{' FunctionBody '}' { $$ = new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, $5); DBG($5, @4, @6); }
+ | FUNCTION '(' FormalParameterList ')' '{' FunctionBody '}' { $$ = new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, $6, $3.head); DBG($6, @5, @7); }
+ | FUNCTION IDENT '(' ')' '{' FunctionBody '}' { $$ = new FuncExprNode(*$2, $6); DBG($6, @5, @7); }
+ | FUNCTION IDENT '(' FormalParameterList ')' '{' FunctionBody '}' { $$ = new FuncExprNode(*$2, $7, $4.head); DBG($7, @6, @8); }
+;
+
+FormalParameterList:
+ IDENT { $$.head = new ParameterNode(*$1);
+ $$.tail = $$.head; }
+ | FormalParameterList ',' IDENT { $$.head = $1.head;
+ $$.tail = new ParameterNode($1.tail, *$3); }
+;
+
+FunctionBody:
+ /* not in spec */ { $$ = FunctionBodyNode::create(0, 0, 0); }
+ | SourceElements { $$ = FunctionBodyNode::create($1.m_node, $1.m_varDeclarations ? &$1.m_varDeclarations->data : 0,
+ $1.m_funcDeclarations ? &$1.m_funcDeclarations->data : 0);
+ // As in mergeDeclarationLists() we have to ref/deref to safely get rid of
+ // the declaration lists.
+ if ($1.m_varDeclarations) {
+ $1.m_varDeclarations->ref();
+ $1.m_varDeclarations->deref();
+ }
+ if ($1.m_funcDeclarations) {
+ $1.m_funcDeclarations->ref();
+ $1.m_funcDeclarations->deref();
+ }
+ }
+;
+
+Program:
+ /* not in spec */ { parser().didFinishParsing(0, 0, 0, @0.last_line); }
+ | SourceElements { parser().didFinishParsing($1.m_node, $1.m_varDeclarations, $1.m_funcDeclarations, @1.last_line); }
+;
+
+SourceElements:
+ SourceElement { $$.m_node = new SourceElements;
+ $$.m_node->append($1.m_node);
+ $$.m_varDeclarations = $1.m_varDeclarations;
+ $$.m_funcDeclarations = $1.m_funcDeclarations;
+ }
+ | SourceElements SourceElement { $$.m_node->append($2.m_node);
+ $$.m_varDeclarations = mergeDeclarationLists($1.m_varDeclarations, $2.m_varDeclarations);
+ $$.m_funcDeclarations = mergeDeclarationLists($1.m_funcDeclarations, $2.m_funcDeclarations);
+ }
+;
+
+SourceElement:
+ FunctionDeclaration { $$ = createNodeInfo<StatementNode*>($1, 0, new ParserRefCountedData<DeclarationStacks::FunctionStack>); $$.m_funcDeclarations->data.append($1); }
+ | Statement { $$ = $1; }
+;
+
+%%
+
+static AddNode* makeAddNode(ExpressionNode* left, ExpressionNode* right)
+{
+ JSType t1 = left->expectedReturnType();
+ JSType t2 = right->expectedReturnType();
+
+ if (t1 == NumberType && t2 == NumberType)
+ return new AddNumbersNode(left, right);
+ if (t1 == StringType && t2 == StringType)
+ return new AddStringsNode(left, right);
+ if (t1 == StringType)
+ return new AddStringLeftNode(left, right);
+ if (t2 == StringType)
+ return new AddStringRightNode(left, right);
+ return new AddNode(left, right);
+}
+
+static LessNode* makeLessNode(ExpressionNode* left, ExpressionNode* right)
+{
+ JSType t1 = left->expectedReturnType();
+ JSType t2 = right->expectedReturnType();
+
+ if (t1 == StringType && t2 == StringType)
+ return new LessStringsNode(left, right);
+
+ // There are certainly more efficient ways to do this type check if necessary
+ if (t1 == NumberType || t1 == BooleanType || t1 == UndefinedType || t1 == NullType ||
+ t2 == NumberType || t2 == BooleanType || t2 == UndefinedType || t2 == NullType)
+ return new LessNumbersNode(left, right);
+
+ // Neither is certain to be a number, nor were both certain to be strings, so we use the default (slow) implementation.
+ return new LessNode(left, right);
+}
+
+static ExpressionNode* makeAssignNode(ExpressionNode* loc, Operator op, ExpressionNode* expr)
+{
+ if (!loc->isLocation())
+ return new AssignErrorNode(loc, op, expr);
+
+ if (loc->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(loc);
+ if (op == OpEqual)
+ return new AssignResolveNode(resolve->identifier(), expr);
+ else
+ return new ReadModifyResolveNode(resolve->identifier(), op, expr);
+ }
+ if (loc->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc);
+ if (op == OpEqual)
+ return new AssignBracketNode(bracket->base(), bracket->subscript(), expr);
+ else
+ return new ReadModifyBracketNode(bracket->base(), bracket->subscript(), op, expr);
+ }
+ ASSERT(loc->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc);
+ if (op == OpEqual)
+ return new AssignDotNode(dot->base(), dot->identifier(), expr);
+ return new ReadModifyDotNode(dot->base(), dot->identifier(), op, expr);
+}
+
+static ExpressionNode* makePrefixNode(ExpressionNode* expr, Operator op)
+{
+ if (!expr->isLocation())
+ return new PrefixErrorNode(expr, op);
+
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ if (op == OpPlusPlus)
+ return new PreIncResolveNode(resolve->identifier());
+ else
+ return new PreDecResolveNode(resolve->identifier());
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ if (op == OpPlusPlus)
+ return new PreIncBracketNode(bracket->base(), bracket->subscript());
+ else
+ return new PreDecBracketNode(bracket->base(), bracket->subscript());
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ if (op == OpPlusPlus)
+ return new PreIncDotNode(dot->base(), dot->identifier());
+ return new PreDecDotNode(dot->base(), dot->identifier());
+}
+
+static ExpressionNode* makePostfixNode(ExpressionNode* expr, Operator op)
+{
+ if (!expr->isLocation())
+ return new PostfixErrorNode(expr, op);
+
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ if (op == OpPlusPlus)
+ return new PostIncResolveNode(resolve->identifier());
+ else
+ return new PostDecResolveNode(resolve->identifier());
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ if (op == OpPlusPlus)
+ return new PostIncBracketNode(bracket->base(), bracket->subscript());
+ else
+ return new PostDecBracketNode(bracket->base(), bracket->subscript());
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+
+ if (op == OpPlusPlus)
+ return new PostIncDotNode(dot->base(), dot->identifier());
+ return new PostDecDotNode(dot->base(), dot->identifier());
+}
+
+static ExpressionNode* makeFunctionCallNode(ExpressionNode* func, ArgumentsNode* args)
+{
+ if (!func->isLocation())
+ return new FunctionCallValueNode(func, args);
+ if (func->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(func);
+ return new FunctionCallResolveNode(resolve->identifier(), args);
+ }
+ if (func->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func);
+ return new FunctionCallBracketNode(bracket->base(), bracket->subscript(), args);
+ }
+ ASSERT(func->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(func);
+ return new FunctionCallDotNode(dot->base(), dot->identifier(), args);
+}
+
+static ExpressionNode* makeTypeOfNode(ExpressionNode* expr)
+{
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new TypeOfResolveNode(resolve->identifier());
+ }
+ return new TypeOfValueNode(expr);
+}
+
+static ExpressionNode* makeDeleteNode(ExpressionNode* expr)
+{
+ if (!expr->isLocation())
+ return new DeleteValueNode(expr);
+ if (expr->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(expr);
+ return new DeleteResolveNode(resolve->identifier());
+ }
+ if (expr->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
+ return new DeleteBracketNode(bracket->base(), bracket->subscript());
+ }
+ ASSERT(expr->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
+ return new DeleteDotNode(dot->base(), dot->identifier());
+}
+
+static PropertyNode* makeGetterOrSetterPropertyNode(const Identifier& getOrSet, const Identifier& name, ParameterNode* params, FunctionBodyNode* body)
+{
+ PropertyNode::Type type;
+ if (getOrSet == "get")
+ type = PropertyNode::Getter;
+ else if (getOrSet == "set")
+ type = PropertyNode::Setter;
+ else
+ return 0;
+ return new PropertyNode(name, new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, body, params), type);
+}
+
+static ExpressionNode* makeNegateNode(ExpressionNode* n)
+{
+ if (n->isNumber()) {
+ NumberNode* number = static_cast<NumberNode*>(n);
+
+ if (number->value() > 0.0) {
+ number->setValue(-number->value());
+ return number;
+ }
+ }
+
+ return new NegateNode(n);
+}
+
+static NumberNode* makeNumberNode(double d)
+{
+ JSValue* value = JSImmediate::from(d);
+ if (value)
+ return new ImmediateNumberNode(value, d);
+ return new NumberNode(d);
+}
+
+/* called by yyparse on error */
+int yyerror(const char *)
+{
+ return 1;
+}
+
+/* may we automatically insert a semicolon ? */
+static bool allowAutomaticSemicolon()
+{
+ return yychar == '}' || yychar == 0 || lexer().prevTerminator();
+}
+
+static ExpressionNode* combineVarInitializers(ExpressionNode* list, AssignResolveNode* init)
+{
+ if (!list)
+ return init;
+ return new VarDeclCommaNode(list, init);
+}
+
+// We turn variable declarations into either assignments or empty
+// statements (which later get stripped out), because the actual
+// declaration work is hoisted up to the start of the function body
+static StatementNode* makeVarStatementNode(ExpressionNode* expr)
+{
+ if (!expr)
+ return new EmptyStatementNode();
+ return new VarStatementNode(expr);
+}
+
diff --git a/JavaScriptCore/kjs/identifier.cpp b/JavaScriptCore/kjs/identifier.cpp
new file mode 100644
index 0000000..3fa01ad
--- /dev/null
+++ b/JavaScriptCore/kjs/identifier.cpp
@@ -0,0 +1,205 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2003 Apple Computer, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+
+#include "identifier.h"
+
+#include "JSLock.h"
+#include <new> // for placement new
+#include <string.h> // for strlen
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/HashSet.h>
+
+namespace WTF {
+
+ template<typename T> struct DefaultHash;
+ template<typename T> struct StrHash;
+
+ template<> struct StrHash<KJS::UString::Rep *> {
+ static unsigned hash(const KJS::UString::Rep *key) { return key->hash(); }
+ static bool equal(const KJS::UString::Rep *a, const KJS::UString::Rep *b) { return KJS::Identifier::equal(a, b); }
+ static const bool safeToCompareToEmptyOrDeleted = false;
+ };
+
+ template<> struct DefaultHash<KJS::UString::Rep *> {
+ typedef StrHash<KJS::UString::Rep *> Hash;
+ };
+
+}
+
+namespace KJS {
+
+typedef HashSet<UString::Rep *> IdentifierTable;
+static IdentifierTable *table;
+
+static inline IdentifierTable& identifierTable()
+{
+ ASSERT(JSLock::lockCount() > 0);
+
+ if (!table)
+ table = new IdentifierTable;
+ return *table;
+}
+
+
+bool Identifier::equal(const UString::Rep *r, const char *s)
+{
+ int length = r->len;
+ const UChar *d = r->data();
+ for (int i = 0; i != length; ++i)
+ if (d[i].uc != (unsigned char)s[i])
+ return false;
+ return s[length] == 0;
+}
+
+bool Identifier::equal(const UString::Rep *r, const UChar *s, int length)
+{
+ if (r->len != length)
+ return false;
+ const UChar *d = r->data();
+ for (int i = 0; i != length; ++i)
+ if (d[i].uc != s[i].uc)
+ return false;
+ return true;
+}
+
+bool Identifier::equal(const UString::Rep *r, const UString::Rep *b)
+{
+ int length = r->len;
+ if (length != b->len)
+ return false;
+ const UChar *d = r->data();
+ const UChar *s = b->data();
+ for (int i = 0; i != length; ++i)
+ if (d[i].uc != s[i].uc)
+ return false;
+ return true;
+}
+
+struct CStringTranslator
+{
+ static unsigned hash(const char *c)
+ {
+ return UString::Rep::computeHash(c);
+ }
+
+ static bool equal(UString::Rep *r, const char *s)
+ {
+ return Identifier::equal(r, s);
+ }
+
+ static void translate(UString::Rep*& location, const char *c, unsigned hash)
+ {
+ size_t length = strlen(c);
+ UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * length));
+ for (size_t i = 0; i != length; i++)
+ d[i] = c[i];
+
+ UString::Rep *r = UString::Rep::create(d, static_cast<int>(length)).releaseRef();
+ r->isIdentifier = 1;
+ r->rc = 0;
+ r->_hash = hash;
+
+ location = r;
+ }
+};
+
+PassRefPtr<UString::Rep> Identifier::add(const char *c)
+{
+ if (!c) {
+ UString::Rep::null.hash();
+ return &UString::Rep::null;
+ }
+
+ if (!c[0]) {
+ UString::Rep::empty.hash();
+ return &UString::Rep::empty;
+ }
+
+ return *identifierTable().add<const char *, CStringTranslator>(c).first;
+}
+
+struct UCharBuffer {
+ const UChar *s;
+ unsigned int length;
+};
+
+struct UCharBufferTranslator
+{
+ static unsigned hash(const UCharBuffer& buf)
+ {
+ return UString::Rep::computeHash(buf.s, buf.length);
+ }
+
+ static bool equal(UString::Rep *str, const UCharBuffer& buf)
+ {
+ return Identifier::equal(str, buf.s, buf.length);
+ }
+
+ static void translate(UString::Rep *& location, const UCharBuffer& buf, unsigned hash)
+ {
+ UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * buf.length));
+ for (unsigned i = 0; i != buf.length; i++)
+ d[i] = buf.s[i];
+
+ UString::Rep *r = UString::Rep::create(d, buf.length).releaseRef();
+ r->isIdentifier = 1;
+ r->rc = 0;
+ r->_hash = hash;
+
+ location = r;
+ }
+};
+
+PassRefPtr<UString::Rep> Identifier::add(const UChar *s, int length)
+{
+ if (!length) {
+ UString::Rep::empty.hash();
+ return &UString::Rep::empty;
+ }
+
+ UCharBuffer buf = {s, length};
+ return *identifierTable().add<UCharBuffer, UCharBufferTranslator>(buf).first;
+}
+
+PassRefPtr<UString::Rep> Identifier::addSlowCase(UString::Rep *r)
+{
+ ASSERT(!r->isIdentifier);
+
+ if (r->len == 0) {
+ UString::Rep::empty.hash();
+ return &UString::Rep::empty;
+ }
+
+ UString::Rep *result = *identifierTable().add(r).first;
+ if (result == r)
+ r->isIdentifier = true;
+ return result;
+}
+
+void Identifier::remove(UString::Rep *r)
+{
+ identifierTable().remove(r);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/identifier.h b/JavaScriptCore/kjs/identifier.h
new file mode 100644
index 0000000..fc43344
--- /dev/null
+++ b/JavaScriptCore/kjs/identifier.h
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_IDENTIFIER_H
+#define KJS_IDENTIFIER_H
+
+#include "ustring.h"
+
+namespace KJS {
+
+ class Identifier {
+ friend class PropertyMap;
+ public:
+ Identifier() { }
+ Identifier(const char* s) : _ustring(add(s)) { }
+ Identifier(const UChar* s, int length) : _ustring(add(s, length)) { }
+ explicit Identifier(UString::Rep* rep) : _ustring(add(rep)) { }
+ explicit Identifier(const UString& s) : _ustring(add(s.rep())) { }
+
+ // Special constructor for cases where we overwrite an object in place.
+ Identifier(PlacementNewAdoptType) : _ustring(PlacementNewAdopt) { }
+
+ const UString& ustring() const { return _ustring; }
+ DOM::DOMString domString() const;
+
+ const UChar* data() const { return _ustring.data(); }
+ int size() const { return _ustring.size(); }
+
+ const char* ascii() const { return _ustring.ascii(); }
+
+ static Identifier from(unsigned y) { return Identifier(UString::from(y)); }
+
+ bool isNull() const { return _ustring.isNull(); }
+ bool isEmpty() const { return _ustring.isEmpty(); }
+
+ uint32_t toUInt32(bool* ok) const { return _ustring.toUInt32(ok); }
+ uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const { return _ustring.toUInt32(ok, tolerateEmptyString); };
+ uint32_t toStrictUInt32(bool* ok) const { return _ustring.toStrictUInt32(ok); }
+ unsigned toArrayIndex(bool* ok) const { return _ustring.toArrayIndex(ok); }
+ double toDouble() const { return _ustring.toDouble(); }
+
+ friend bool operator==(const Identifier&, const Identifier&);
+ friend bool operator!=(const Identifier&, const Identifier&);
+
+ friend bool operator==(const Identifier&, const char*);
+
+ static void remove(UString::Rep* );
+
+ static bool equal(const UString::Rep*, const char*);
+ static bool equal(const UString::Rep*, const UChar*, int length);
+ static bool equal(const UString::Rep*, const UString::Rep*);
+
+ private:
+ UString _ustring;
+
+ static bool equal(const Identifier& a, const Identifier& b)
+ { return a._ustring.rep() == b._ustring.rep(); }
+ static bool equal(const Identifier& a, const char* b)
+ { return equal(a._ustring.rep(), b); }
+
+ static PassRefPtr<UString::Rep> add(const char*);
+ static PassRefPtr<UString::Rep> add(const UChar*, int length);
+ static PassRefPtr<UString::Rep> add(UString::Rep* r)
+ {
+ if (r->isIdentifier)
+ return r;
+ return addSlowCase(r);
+ }
+ static PassRefPtr<UString::Rep> addSlowCase(UString::Rep *r);
+ };
+
+ inline bool operator==(const Identifier& a, const Identifier& b)
+ { return Identifier::equal(a, b); }
+
+ inline bool operator!=(const Identifier& a, const Identifier& b)
+ { return !Identifier::equal(a, b); }
+
+ inline bool operator==(const Identifier& a, const char* b)
+ { return Identifier::equal(a, b); }
+
+} // namespace KJS
+
+#endif // KJS_IDENTIFIER_H
diff --git a/JavaScriptCore/kjs/internal.cpp b/JavaScriptCore/kjs/internal.cpp
new file mode 100644
index 0000000..5482b48
--- /dev/null
+++ b/JavaScriptCore/kjs/internal.cpp
@@ -0,0 +1,302 @@
+/*
+ * 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 "internal.h"
+
+#include "ExecState.h"
+#include "array_object.h"
+#include "bool_object.h"
+#include "collector.h"
+#include "date_object.h"
+#include "debugger.h"
+#include "error_object.h"
+#include "function_object.h"
+#include "lexer.h"
+#include "math_object.h"
+#include "nodes.h"
+#include "number_object.h"
+#include "object.h"
+#include "object_object.h"
+#include "operations.h"
+#include "regexp_object.h"
+#include "string_object.h"
+#include <math.h>
+#include <stdio.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashMap.h>
+#include <wtf/HashSet.h>
+#include <wtf/Vector.h>
+
+namespace KJS {
+
+// ------------------------------ StringImp ------------------------------------
+
+JSValue* StringImp::toPrimitive(ExecState*, JSType) const
+{
+ return const_cast<StringImp*>(this);
+}
+
+bool StringImp::getPrimitiveNumber(ExecState*, double& number, JSValue*& value)
+{
+ value = this;
+ number = val.toDouble();
+ return false;
+}
+
+bool StringImp::toBoolean(ExecState *) const
+{
+ return (val.size() > 0);
+}
+
+double StringImp::toNumber(ExecState *) const
+{
+ return val.toDouble();
+}
+
+UString StringImp::toString(ExecState *) const
+{
+ return val;
+}
+
+JSObject* StringImp::toObject(ExecState *exec) const
+{
+ return new StringInstance(exec->lexicalGlobalObject()->stringPrototype(), const_cast<StringImp*>(this));
+}
+
+// ------------------------------ NumberImp ------------------------------------
+
+JSValue* NumberImp::toPrimitive(ExecState*, JSType) const
+{
+ return const_cast<NumberImp*>(this);
+}
+
+bool NumberImp::getPrimitiveNumber(ExecState*, double& number, JSValue*& value)
+{
+ number = val;
+ value = this;
+ return true;
+}
+
+bool NumberImp::toBoolean(ExecState *) const
+{
+ return val < 0.0 || val > 0.0; // false for NaN
+}
+
+double NumberImp::toNumber(ExecState *) const
+{
+ return val;
+}
+
+UString NumberImp::toString(ExecState *) const
+{
+ if (val == 0.0) // +0.0 or -0.0
+ return "0";
+ return UString::from(val);
+}
+
+JSObject *NumberImp::toObject(ExecState *exec) const
+{
+ List args;
+ args.append(const_cast<NumberImp*>(this));
+ return static_cast<JSObject *>(exec->lexicalGlobalObject()->numberConstructor()->construct(exec,args));
+}
+
+bool NumberImp::getUInt32(uint32_t& uint32) const
+{
+ uint32 = static_cast<uint32_t>(val);
+ return uint32 == val;
+}
+
+bool NumberImp::getTruncatedInt32(int32_t& int32) const
+{
+ if (!(val >= -2147483648.0 && val < 2147483648.0))
+ return false;
+ int32 = static_cast<int32_t>(val);
+ return true;
+}
+
+bool NumberImp::getTruncatedUInt32(uint32_t& uint32) const
+{
+ if (!(val >= 0.0 && val < 4294967296.0))
+ return false;
+ uint32 = static_cast<uint32_t>(val);
+ return true;
+}
+
+// --------------------------- GetterSetterImp ---------------------------------
+void GetterSetterImp::mark()
+{
+ JSCell::mark();
+
+ if (getter && !getter->marked())
+ getter->mark();
+ if (setter && !setter->marked())
+ setter->mark();
+}
+
+JSValue* GetterSetterImp::toPrimitive(ExecState*, JSType) const
+{
+ ASSERT(false);
+ return jsNull();
+}
+
+bool GetterSetterImp::getPrimitiveNumber(ExecState*, double& number, JSValue*& value)
+{
+ ASSERT_NOT_REACHED();
+ number = 0;
+ value = 0;
+ return true;
+}
+
+bool GetterSetterImp::toBoolean(ExecState*) const
+{
+ ASSERT(false);
+ return false;
+}
+
+double GetterSetterImp::toNumber(ExecState *) const
+{
+ ASSERT(false);
+ return 0.0;
+}
+
+UString GetterSetterImp::toString(ExecState *) const
+{
+ ASSERT(false);
+ return UString::null();
+}
+
+JSObject *GetterSetterImp::toObject(ExecState *exec) const
+{
+ ASSERT(false);
+ return jsNull()->toObject(exec);
+}
+
+// ------------------------------ LabelStack -----------------------------------
+
+bool LabelStack::push(const Identifier &id)
+{
+ if (contains(id))
+ return false;
+
+ StackElem *newtos = new StackElem;
+ newtos->id = id;
+ newtos->prev = tos;
+ tos = newtos;
+ return true;
+}
+
+bool LabelStack::contains(const Identifier &id) const
+{
+ if (id.isEmpty())
+ return true;
+
+ for (StackElem *curr = tos; curr; curr = curr->prev)
+ if (curr->id == id)
+ return true;
+
+ return false;
+}
+
+// ------------------------------ InternalFunctionImp --------------------------
+
+const ClassInfo InternalFunctionImp::info = { "Function", 0, 0 };
+
+InternalFunctionImp::InternalFunctionImp()
+{
+}
+
+InternalFunctionImp::InternalFunctionImp(FunctionPrototype* funcProto, const Identifier& name)
+ : JSObject(funcProto)
+ , m_name(name)
+{
+}
+
+bool InternalFunctionImp::implementsCall() const
+{
+ return true;
+}
+
+bool InternalFunctionImp::implementsHasInstance() const
+{
+ return true;
+}
+
+// ------------------------------ global functions -----------------------------
+
+#ifndef NDEBUG
+#include <stdio.h>
+void printInfo(ExecState *exec, const char *s, JSValue *o, int lineno)
+{
+ if (!o)
+ fprintf(stderr, "KJS: %s: (null)", s);
+ else {
+ JSValue *v = o;
+
+ UString name;
+ switch (v->type()) {
+ case UnspecifiedType:
+ name = "Unspecified";
+ break;
+ case UndefinedType:
+ name = "Undefined";
+ break;
+ case NullType:
+ name = "Null";
+ break;
+ case BooleanType:
+ name = "Boolean";
+ break;
+ case StringType:
+ name = "String";
+ break;
+ case NumberType:
+ name = "Number";
+ break;
+ case ObjectType:
+ name = static_cast<JSObject *>(v)->className();
+ if (name.isNull())
+ name = "(unknown class)";
+ break;
+ case GetterSetterType:
+ name = "GetterSetter";
+ break;
+ }
+ UString vString = v->toString(exec);
+ if ( vString.size() > 50 )
+ vString = vString.substr( 0, 50 ) + "...";
+ // Can't use two UString::ascii() in the same fprintf call
+ CString tempString( vString.cstring() );
+
+ fprintf(stderr, "KJS: %s: %s : %s (%p)",
+ s, tempString.c_str(), name.ascii(), (void*)v);
+
+ if (lineno >= 0)
+ fprintf(stderr, ", line %d\n",lineno);
+ else
+ fprintf(stderr, "\n");
+ }
+}
+#endif
+
+}
diff --git a/JavaScriptCore/kjs/internal.h b/JavaScriptCore/kjs/internal.h
new file mode 100644
index 0000000..d3a2eb2
--- /dev/null
+++ b/JavaScriptCore/kjs/internal.h
@@ -0,0 +1,117 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef INTERNAL_H
+#define INTERNAL_H
+
+#include "JSType.h"
+#include "object.h"
+#include "protect.h"
+#include "scope_chain.h"
+#include "types.h"
+#include "ustring.h"
+
+#include <wtf/Noncopyable.h>
+
+#define I18N_NOOP(s) s
+
+namespace KJS {
+
+ class FunctionPrototype;
+
+ // ---------------------------------------------------------------------------
+ // Primitive impls
+ // ---------------------------------------------------------------------------
+
+ class StringImp : public JSCell {
+ public:
+ StringImp(const UString& v) : val(v) { Collector::reportExtraMemoryCost(v.cost()); }
+ enum HasOtherOwnerType { HasOtherOwner };
+ StringImp(const UString& value, HasOtherOwnerType) : val(value) { }
+ const UString& value() const { return val; }
+
+ private:
+ virtual JSType type() const { return StringType; }
+
+ virtual JSValue* toPrimitive(ExecState*, JSType preferred = UnspecifiedType) const;
+ virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
+ virtual bool toBoolean(ExecState *exec) const;
+ virtual double toNumber(ExecState *exec) const;
+ virtual JSObject *toObject(ExecState *exec) const;
+ virtual UString toString(ExecState*) const;
+
+ UString val;
+ };
+
+ class NumberImp : public JSCell {
+ friend class ConstantValues;
+ friend JSValue *jsNumberCell(double);
+ public:
+ double value() const { return val; }
+
+ virtual JSType type() const { return NumberType; }
+
+ virtual JSValue* toPrimitive(ExecState*, JSType preferred = UnspecifiedType) const;
+ virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
+ virtual bool toBoolean(ExecState *exec) const;
+ virtual double toNumber(ExecState *exec) const;
+ virtual UString toString(ExecState *exec) const;
+ virtual JSObject *toObject(ExecState *exec) const;
+
+ void* operator new(size_t size)
+ {
+ return Collector::allocateNumber(size);
+ }
+ private:
+ NumberImp(double v) : val(v) { }
+
+ virtual bool getUInt32(uint32_t&) const;
+ virtual bool getTruncatedInt32(int32_t&) const;
+ virtual bool getTruncatedUInt32(uint32_t&) const;
+
+ double val;
+ };
+
+
+ // ---------------------------------------------------------------------------
+ // Evaluation
+ // ---------------------------------------------------------------------------
+
+ struct AttachedGlobalObject;
+ class DebuggerImp {
+ public:
+
+ DebuggerImp() {
+ globalObjects = 0;
+ }
+
+ AttachedGlobalObject* globalObjects;
+ };
+
+#ifndef NDEBUG
+ void printInfo(ExecState *exec, const char *s, JSValue *, int lineno = -1);
+#endif
+
+} // namespace
+
+#endif // INTERNAL_H
diff --git a/JavaScriptCore/kjs/interpreter.cpp b/JavaScriptCore/kjs/interpreter.cpp
new file mode 100644
index 0000000..a15b6d3
--- /dev/null
+++ b/JavaScriptCore/kjs/interpreter.cpp
@@ -0,0 +1,159 @@
+/*
+ * 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 "interpreter.h"
+
+#include "ExecState.h"
+#include "JSGlobalObject.h"
+#include "Parser.h"
+#include "SavedBuiltins.h"
+#include "array_object.h"
+#include "bool_object.h"
+#include "collector.h"
+#include "date_object.h"
+#include "debugger.h"
+#include "error_object.h"
+#include "function_object.h"
+#include "internal.h"
+#include "math_object.h"
+#include "nodes.h"
+#include "number_object.h"
+#include "object.h"
+#include "object_object.h"
+#include "operations.h"
+#include "regexp_object.h"
+#include "runtime.h"
+#include "string_object.h"
+#include "types.h"
+#include "value.h"
+#include <math.h>
+#include <signal.h>
+#include <stdio.h>
+#include <wtf/Assertions.h>
+
+#if !PLATFORM(WIN_OS)
+#include <unistd.h>
+#endif
+
+namespace KJS {
+
+Completion Interpreter::checkSyntax(ExecState* exec, const UString& sourceURL, int startingLineNumber, const UString& code)
+{
+ return checkSyntax(exec, sourceURL, startingLineNumber, code.data(), code.size());
+}
+
+Completion Interpreter::checkSyntax(ExecState* exec, const UString& sourceURL, int startingLineNumber, const UChar* code, int codeLength)
+{
+ JSLock lock;
+
+ int errLine;
+ UString errMsg;
+ RefPtr<ProgramNode> progNode = parser().parse<ProgramNode>(sourceURL, startingLineNumber, code, codeLength, 0, &errLine, &errMsg);
+ if (!progNode)
+ return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, 0, sourceURL));
+ return Completion(Normal);
+}
+
+Completion Interpreter::evaluate(ExecState* exec, const UString& sourceURL, int startingLineNumber, const UString& code, JSValue* thisV)
+{
+ return evaluate(exec, sourceURL, startingLineNumber, code.data(), code.size(), thisV);
+}
+
+Completion Interpreter::evaluate(ExecState* exec, const UString& sourceURL, int startingLineNumber, const UChar* code, int codeLength, JSValue* thisV)
+{
+ JSLock lock;
+
+ JSGlobalObject* globalObject = exec->dynamicGlobalObject();
+
+ if (globalObject->recursion() >= 20)
+ return Completion(Throw, Error::create(exec, GeneralError, "Recursion too deep"));
+
+ // parse the source code
+ int sourceId;
+ int errLine;
+ UString errMsg;
+ RefPtr<ProgramNode> progNode = parser().parse<ProgramNode>(sourceURL, startingLineNumber, code, codeLength, &sourceId, &errLine, &errMsg);
+
+ // notify debugger that source has been parsed
+ if (globalObject->debugger()) {
+ bool cont = globalObject->debugger()->sourceParsed(exec, sourceId, sourceURL, UString(code, codeLength), startingLineNumber, errLine, errMsg);
+ if (!cont)
+ return Completion(Break);
+ }
+
+ // no program node means a syntax error occurred
+ if (!progNode)
+ return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, sourceId, sourceURL));
+
+ exec->clearException();
+
+ globalObject->incRecursion();
+
+ JSObject* thisObj = globalObject;
+
+ // "this" must be an object... use same rules as Function.prototype.apply()
+ if (thisV && !thisV->isUndefinedOrNull())
+ thisObj = thisV->toObject(exec);
+
+ Completion res;
+ if (exec->hadException())
+ // the thisV->toObject() conversion above might have thrown an exception - if so, propagate it
+ res = Completion(Throw, exec->exception());
+ else {
+ // execute the code
+ InterpreterExecState newExec(globalObject, thisObj, progNode.get());
+ JSValue* value = progNode->execute(&newExec);
+ res = Completion(newExec.completionType(), value);
+ }
+
+ globalObject->decRecursion();
+
+ if (shouldPrintExceptions() && res.complType() == Throw) {
+ JSLock lock;
+ ExecState* exec = globalObject->globalExec();
+ CString f = sourceURL.UTF8String();
+ CString message = res.value()->toObject(exec)->toString(exec).UTF8String();
+ int line = res.value()->toObject(exec)->get(exec, "line")->toUInt32(exec);
+#if PLATFORM(WIN_OS)
+ printf("%s line %d: %s\n", f.c_str(), line, message.c_str());
+#else
+ printf("[%d] %s line %d: %s\n", getpid(), f.c_str(), line, message.c_str());
+#endif
+ }
+
+ return res;
+}
+
+static bool printExceptions = false;
+
+bool Interpreter::shouldPrintExceptions()
+{
+ return printExceptions;
+}
+
+void Interpreter::setShouldPrintExceptions(bool print)
+{
+ printExceptions = print;
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/interpreter.h b/JavaScriptCore/kjs/interpreter.h
new file mode 100644
index 0000000..79b9398
--- /dev/null
+++ b/JavaScriptCore/kjs/interpreter.h
@@ -0,0 +1,71 @@
+/*
+ * 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 KJS_Interpreter_h
+#define KJS_Interpreter_h
+
+namespace KJS {
+
+ class Completion;
+ class ExecState;
+ class JSValue;
+ class UString;
+
+ struct UChar;
+
+ class Interpreter {
+ public:
+ /**
+ * Parses the supplied ECMAScript code and checks for syntax errors.
+ *
+ * @param code The code to check
+ * @return A normal completion if there were no syntax errors in the code,
+ * otherwise a throw completion with the syntax error as its value.
+ */
+ static Completion checkSyntax(ExecState*, const UString& sourceURL, int startingLineNumber, const UString& code);
+ static Completion checkSyntax(ExecState*, const UString& sourceURL, int startingLineNumber, const UChar* code, int codeLength);
+
+ /**
+ * Evaluates the supplied ECMAScript code.
+ *
+ * Since this method returns a Completion, you should check the type of
+ * completion to detect an error or before attempting to access the returned
+ * value. For example, if an error occurs during script execution and is not
+ * caught by the script, the completion type will be Throw.
+ *
+ * If the supplied code is invalid, a SyntaxError will be thrown.
+ *
+ * @param code The code to evaluate
+ * @param thisV The value to pass in as the "this" value for the script
+ * execution. This should either be jsNull() or an Object.
+ * @return A completion object representing the result of the execution.
+ */
+ static Completion evaluate(ExecState*, const UString& sourceURL, int startingLineNumber, const UString& code, JSValue* thisV = 0);
+ static Completion evaluate(ExecState*, const UString& sourceURL, int startingLineNumber, const UChar* code, int codeLength, JSValue* thisV = 0);
+
+ static bool shouldPrintExceptions();
+ static void setShouldPrintExceptions(bool);
+ };
+
+} // namespace KJS
+
+#endif // KJS_Interpreter_h
diff --git a/JavaScriptCore/kjs/keywords.table b/JavaScriptCore/kjs/keywords.table
new file mode 100644
index 0000000..490c1cc
--- /dev/null
+++ b/JavaScriptCore/kjs/keywords.table
@@ -0,0 +1,72 @@
+# main keywords
+@begin mainTable 41
+
+# types
+null NULLTOKEN
+true TRUETOKEN
+false FALSETOKEN
+
+# keywords
+break BREAK
+case CASE
+catch CATCH
+const CONSTTOKEN
+default DEFAULT
+finally FINALLY
+for FOR
+instanceof INSTANCEOF
+new NEW
+var VAR
+continue CONTINUE
+function FUNCTION
+return RETURN
+void VOIDTOKEN
+delete DELETETOKEN
+if IF
+this THISTOKEN
+do DO
+while WHILE
+else ELSE
+in INTOKEN
+switch SWITCH
+throw THROW
+try TRY
+typeof TYPEOF
+with WITH
+debugger DEBUGGER
+
+# reserved for future use
+class RESERVED
+enum RESERVED
+export RESERVED
+extends RESERVED
+import RESERVED
+super RESERVED
+
+# these words are reserved for future use in the ECMA spec, but not in WinIE
+# (see http://bugs.webkit.org/show_bug.cgi?id=6179)
+# abstract RESERVED
+# boolean RESERVED
+# byte RESERVED
+# char RESERVED
+# double RESERVED
+# final RESERVED
+# float RESERVED
+# goto RESERVED
+# implements RESERVED
+# int RESERVED
+# interface RESERVED
+# long RESERVED
+# native RESERVED
+# package RESERVED
+# private RESERVED
+# protected RESERVED
+# public RESERVED
+# short RESERVED
+# static RESERVED
+# synchronized RESERVED
+# throws RESERVED
+# transient RESERVED
+# volatile RESERVED
+@end
+
diff --git a/JavaScriptCore/kjs/lexer.cpp b/JavaScriptCore/kjs/lexer.cpp
new file mode 100644
index 0000000..c4d327f
--- /dev/null
+++ b/JavaScriptCore/kjs/lexer.cpp
@@ -0,0 +1,897 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2006, 2007 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ *
+ * 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 "lexer.h"
+
+#include "dtoa.h"
+#include "function.h"
+#include "nodes.h"
+#include "NodeInfo.h"
+#include <ctype.h>
+#include <limits.h>
+#include <string.h>
+#include <wtf/Assertions.h>
+#include <wtf/unicode/Unicode.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+// we can't specify the namespace in yacc's C output, so do it here
+using namespace KJS;
+
+#ifndef KDE_USE_FINAL
+#include "grammar.h"
+#endif
+
+#include "lookup.h"
+#include "lexer.lut.h"
+
+extern YYLTYPE kjsyylloc; // global bison variable holding token info
+
+// a bridge for yacc from the C world to C++
+int kjsyylex()
+{
+ return lexer().lex();
+}
+
+namespace KJS {
+
+static bool isDecimalDigit(int);
+
+static const size_t initialReadBufferCapacity = 32;
+static const size_t initialStringTableCapacity = 64;
+
+Lexer& lexer()
+{
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+
+ // FIXME: We'd like to avoid calling new here, but we don't currently
+ // support tearing down the Lexer at app quit time, since that would involve
+ // tearing down its UString data members without holding the JSLock.
+ static Lexer* staticLexer = new Lexer;
+ return *staticLexer;
+}
+
+Lexer::Lexer()
+ : yylineno(1)
+ , restrKeyword(false)
+ , eatNextIdentifier(false)
+ , stackToken(-1)
+ , lastToken(-1)
+ , pos(0)
+ , code(0)
+ , length(0)
+ , atLineStart(true)
+ , current(0)
+ , next1(0)
+ , next2(0)
+ , next3(0)
+{
+ m_buffer8.reserveCapacity(initialReadBufferCapacity);
+ m_buffer16.reserveCapacity(initialReadBufferCapacity);
+ m_strings.reserveCapacity(initialStringTableCapacity);
+ m_identifiers.reserveCapacity(initialStringTableCapacity);
+}
+
+void Lexer::setCode(int startingLineNumber, const KJS::UChar *c, unsigned int len)
+{
+ yylineno = 1 + startingLineNumber;
+ restrKeyword = false;
+ delimited = false;
+ eatNextIdentifier = false;
+ stackToken = -1;
+ lastToken = -1;
+ pos = 0;
+ code = c;
+ length = len;
+ skipLF = false;
+ skipCR = false;
+ error = false;
+ atLineStart = true;
+
+ // read first characters
+ current = (length > 0) ? code[0].uc : -1;
+ next1 = (length > 1) ? code[1].uc : -1;
+ next2 = (length > 2) ? code[2].uc : -1;
+ next3 = (length > 3) ? code[3].uc : -1;
+}
+
+void Lexer::shift(unsigned int p)
+{
+ // Here would be a good place to strip Cf characters, but that has caused compatibility problems:
+ // <http://bugs.webkit.org/show_bug.cgi?id=10183>.
+ while (p--) {
+ pos++;
+ current = next1;
+ next1 = next2;
+ next2 = next3;
+ next3 = (pos + 3 < length) ? code[pos + 3].uc : -1;
+ }
+}
+
+// called on each new line
+void Lexer::nextLine()
+{
+ yylineno++;
+ atLineStart = true;
+}
+
+void Lexer::setDone(State s)
+{
+ state = s;
+ done = true;
+}
+
+int Lexer::lex()
+{
+ int token = 0;
+ state = Start;
+ unsigned short stringType = 0; // either single or double quotes
+ m_buffer8.clear();
+ m_buffer16.clear();
+ done = false;
+ terminator = false;
+ skipLF = false;
+ skipCR = false;
+
+ // did we push a token on the stack previously ?
+ // (after an automatic semicolon insertion)
+ if (stackToken >= 0) {
+ setDone(Other);
+ token = stackToken;
+ stackToken = 0;
+ }
+
+ while (!done) {
+ if (skipLF && current != '\n') // found \r but not \n afterwards
+ skipLF = false;
+ if (skipCR && current != '\r') // found \n but not \r afterwards
+ skipCR = false;
+ if (skipLF || skipCR) // found \r\n or \n\r -> eat the second one
+ {
+ skipLF = false;
+ skipCR = false;
+ shift(1);
+ }
+ switch (state) {
+ case Start:
+ if (isWhiteSpace()) {
+ // do nothing
+ } else if (current == '/' && next1 == '/') {
+ shift(1);
+ state = InSingleLineComment;
+ } else if (current == '/' && next1 == '*') {
+ shift(1);
+ state = InMultiLineComment;
+ } else if (current == -1) {
+ if (!terminator && !delimited) {
+ // automatic semicolon insertion if program incomplete
+ token = ';';
+ stackToken = 0;
+ setDone(Other);
+ } else
+ setDone(Eof);
+ } else if (isLineTerminator()) {
+ nextLine();
+ terminator = true;
+ if (restrKeyword) {
+ token = ';';
+ setDone(Other);
+ }
+ } else if (current == '"' || current == '\'') {
+ state = InString;
+ stringType = static_cast<unsigned short>(current);
+ } else if (isIdentStart(current)) {
+ record16(current);
+ state = InIdentifierOrKeyword;
+ } else if (current == '\\') {
+ state = InIdentifierStartUnicodeEscapeStart;
+ } else if (current == '0') {
+ record8(current);
+ state = InNum0;
+ } else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InNum;
+ } else if (current == '.' && isDecimalDigit(next1)) {
+ record8(current);
+ state = InDecimal;
+ // <!-- marks the beginning of a line comment (for www usage)
+ } else if (current == '<' && next1 == '!' &&
+ next2 == '-' && next3 == '-') {
+ shift(3);
+ state = InSingleLineComment;
+ // same for -->
+ } else if (atLineStart && current == '-' && next1 == '-' && next2 == '>') {
+ shift(2);
+ state = InSingleLineComment;
+ } else {
+ token = matchPunctuator(current, next1, next2, next3);
+ if (token != -1) {
+ setDone(Other);
+ } else {
+ // cerr << "encountered unknown character" << endl;
+ setDone(Bad);
+ }
+ }
+ break;
+ case InString:
+ if (current == stringType) {
+ shift(1);
+ setDone(String);
+ } else if (isLineTerminator() || current == -1) {
+ setDone(Bad);
+ } else if (current == '\\') {
+ state = InEscapeSequence;
+ } else {
+ record16(current);
+ }
+ break;
+ // Escape Sequences inside of strings
+ case InEscapeSequence:
+ if (isOctalDigit(current)) {
+ if (current >= '0' && current <= '3' &&
+ isOctalDigit(next1) && isOctalDigit(next2)) {
+ record16(convertOctal(current, next1, next2));
+ shift(2);
+ state = InString;
+ } else if (isOctalDigit(current) && isOctalDigit(next1)) {
+ record16(convertOctal('0', current, next1));
+ shift(1);
+ state = InString;
+ } else if (isOctalDigit(current)) {
+ record16(convertOctal('0', '0', current));
+ state = InString;
+ } else {
+ setDone(Bad);
+ }
+ } else if (current == 'x')
+ state = InHexEscape;
+ else if (current == 'u')
+ state = InUnicodeEscape;
+ else if (isLineTerminator()) {
+ nextLine();
+ state = InString;
+ } else {
+ record16(singleEscape(static_cast<unsigned short>(current)));
+ state = InString;
+ }
+ break;
+ case InHexEscape:
+ if (isHexDigit(current) && isHexDigit(next1)) {
+ state = InString;
+ record16(convertHex(current, next1));
+ shift(1);
+ } else if (current == stringType) {
+ record16('x');
+ shift(1);
+ setDone(String);
+ } else {
+ record16('x');
+ record16(current);
+ state = InString;
+ }
+ break;
+ case InUnicodeEscape:
+ if (isHexDigit(current) && isHexDigit(next1) && isHexDigit(next2) && isHexDigit(next3)) {
+ record16(convertUnicode(current, next1, next2, next3));
+ shift(3);
+ state = InString;
+ } else if (current == stringType) {
+ record16('u');
+ shift(1);
+ setDone(String);
+ } else {
+ setDone(Bad);
+ }
+ break;
+ case InSingleLineComment:
+ if (isLineTerminator()) {
+ nextLine();
+ terminator = true;
+ if (restrKeyword) {
+ token = ';';
+ setDone(Other);
+ } else
+ state = Start;
+ } else if (current == -1) {
+ setDone(Eof);
+ }
+ break;
+ case InMultiLineComment:
+ if (current == -1) {
+ setDone(Bad);
+ } else if (isLineTerminator()) {
+ nextLine();
+ } else if (current == '*' && next1 == '/') {
+ state = Start;
+ shift(1);
+ }
+ break;
+ case InIdentifierOrKeyword:
+ case InIdentifier:
+ if (isIdentPart(current))
+ record16(current);
+ else if (current == '\\')
+ state = InIdentifierPartUnicodeEscapeStart;
+ else
+ setDone(state == InIdentifierOrKeyword ? IdentifierOrKeyword : Identifier);
+ break;
+ case InNum0:
+ if (current == 'x' || current == 'X') {
+ record8(current);
+ state = InHex;
+ } else if (current == '.') {
+ record8(current);
+ state = InDecimal;
+ } else if (current == 'e' || current == 'E') {
+ record8(current);
+ state = InExponentIndicator;
+ } else if (isOctalDigit(current)) {
+ record8(current);
+ state = InOctal;
+ } else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InDecimal;
+ } else {
+ setDone(Number);
+ }
+ break;
+ case InHex:
+ if (isHexDigit(current)) {
+ record8(current);
+ } else {
+ setDone(Hex);
+ }
+ break;
+ case InOctal:
+ if (isOctalDigit(current)) {
+ record8(current);
+ }
+ else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InDecimal;
+ } else
+ setDone(Octal);
+ break;
+ case InNum:
+ if (isDecimalDigit(current)) {
+ record8(current);
+ } else if (current == '.') {
+ record8(current);
+ state = InDecimal;
+ } else if (current == 'e' || current == 'E') {
+ record8(current);
+ state = InExponentIndicator;
+ } else
+ setDone(Number);
+ break;
+ case InDecimal:
+ if (isDecimalDigit(current)) {
+ record8(current);
+ } else if (current == 'e' || current == 'E') {
+ record8(current);
+ state = InExponentIndicator;
+ } else
+ setDone(Number);
+ break;
+ case InExponentIndicator:
+ if (current == '+' || current == '-') {
+ record8(current);
+ } else if (isDecimalDigit(current)) {
+ record8(current);
+ state = InExponent;
+ } else
+ setDone(Bad);
+ break;
+ case InExponent:
+ if (isDecimalDigit(current)) {
+ record8(current);
+ } else
+ setDone(Number);
+ break;
+ case InIdentifierStartUnicodeEscapeStart:
+ if (current == 'u')
+ state = InIdentifierStartUnicodeEscape;
+ else
+ setDone(Bad);
+ break;
+ case InIdentifierPartUnicodeEscapeStart:
+ if (current == 'u')
+ state = InIdentifierPartUnicodeEscape;
+ else
+ setDone(Bad);
+ break;
+ case InIdentifierStartUnicodeEscape:
+ if (!isHexDigit(current) || !isHexDigit(next1) || !isHexDigit(next2) || !isHexDigit(next3)) {
+ setDone(Bad);
+ break;
+ }
+ token = convertUnicode(current, next1, next2, next3).uc;
+ shift(3);
+ if (!isIdentStart(token)) {
+ setDone(Bad);
+ break;
+ }
+ record16(token);
+ state = InIdentifier;
+ break;
+ case InIdentifierPartUnicodeEscape:
+ if (!isHexDigit(current) || !isHexDigit(next1) || !isHexDigit(next2) || !isHexDigit(next3)) {
+ setDone(Bad);
+ break;
+ }
+ token = convertUnicode(current, next1, next2, next3).uc;
+ shift(3);
+ if (!isIdentPart(token)) {
+ setDone(Bad);
+ break;
+ }
+ record16(token);
+ state = InIdentifier;
+ break;
+ default:
+ ASSERT(!"Unhandled state in switch statement");
+ }
+
+ // move on to the next character
+ if (!done)
+ shift(1);
+ if (state != Start && state != InSingleLineComment)
+ atLineStart = false;
+ }
+
+ // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
+ if ((state == Number || state == Octal || state == Hex) && isIdentStart(current))
+ state = Bad;
+
+ // terminate string
+ m_buffer8.append('\0');
+
+#ifdef KJS_DEBUG_LEX
+ fprintf(stderr, "line: %d ", lineNo());
+ fprintf(stderr, "yytext (%x): ", m_buffer8[0]);
+ fprintf(stderr, "%s ", buffer8.data());
+#endif
+
+ double dval = 0;
+ if (state == Number) {
+ dval = kjs_strtod(m_buffer8.data(), 0L);
+ } else if (state == Hex) { // scan hex numbers
+ const char* p = m_buffer8.data() + 2;
+ while (char c = *p++) {
+ dval *= 16;
+ dval += convertHex(c);
+ }
+
+ if (dval >= mantissaOverflowLowerBound)
+ dval = parseIntOverflow(m_buffer8.data() + 2, p - (m_buffer8.data() + 3), 16);
+
+ state = Number;
+ } else if (state == Octal) { // scan octal number
+ const char* p = m_buffer8.data() + 1;
+ while (char c = *p++) {
+ dval *= 8;
+ dval += c - '0';
+ }
+
+ if (dval >= mantissaOverflowLowerBound)
+ dval = parseIntOverflow(m_buffer8.data() + 1, p - (m_buffer8.data() + 2), 8);
+
+ state = Number;
+ }
+
+#ifdef KJS_DEBUG_LEX
+ switch (state) {
+ case Eof:
+ printf("(EOF)\n");
+ break;
+ case Other:
+ printf("(Other)\n");
+ break;
+ case Identifier:
+ printf("(Identifier)/(Keyword)\n");
+ break;
+ case String:
+ printf("(String)\n");
+ break;
+ case Number:
+ printf("(Number)\n");
+ break;
+ default:
+ printf("(unknown)");
+ }
+#endif
+
+ if (state != Identifier && eatNextIdentifier)
+ eatNextIdentifier = false;
+
+ restrKeyword = false;
+ delimited = false;
+ kjsyylloc.first_line = yylineno; // ???
+ kjsyylloc.last_line = yylineno;
+
+ switch (state) {
+ case Eof:
+ token = 0;
+ break;
+ case Other:
+ if(token == '}' || token == ';') {
+ delimited = true;
+ }
+ break;
+ case IdentifierOrKeyword:
+ if ((token = Lookup::find(&mainTable, m_buffer16.data(), m_buffer16.size())) < 0) {
+ case Identifier:
+ // Lookup for keyword failed, means this is an identifier
+ // Apply anonymous-function hack below (eat the identifier)
+ if (eatNextIdentifier) {
+ eatNextIdentifier = false;
+ token = lex();
+ break;
+ }
+ kjsyylval.ident = makeIdentifier(m_buffer16);
+ token = IDENT;
+ break;
+ }
+
+ eatNextIdentifier = false;
+ // Hack for "f = function somename() { ... }", too hard to get into the grammar
+ if (token == FUNCTION && lastToken == '=' )
+ eatNextIdentifier = true;
+
+ if (token == CONTINUE || token == BREAK ||
+ token == RETURN || token == THROW)
+ restrKeyword = true;
+ break;
+ case String:
+ kjsyylval.string = makeUString(m_buffer16);
+ token = STRING;
+ break;
+ case Number:
+ kjsyylval.doubleValue = dval;
+ token = NUMBER;
+ break;
+ case Bad:
+#ifdef KJS_DEBUG_LEX
+ fprintf(stderr, "yylex: ERROR.\n");
+#endif
+ error = true;
+ return -1;
+ default:
+ ASSERT(!"unhandled numeration value in switch");
+ error = true;
+ return -1;
+ }
+ lastToken = token;
+ return token;
+}
+
+bool Lexer::isWhiteSpace() const
+{
+ return current == '\t' || current == 0x0b || current == 0x0c || isSeparatorSpace(current);
+}
+
+bool Lexer::isLineTerminator()
+{
+ bool cr = (current == '\r');
+ bool lf = (current == '\n');
+ if (cr)
+ skipLF = true;
+ else if (lf)
+ skipCR = true;
+ return cr || lf || current == 0x2028 || current == 0x2029;
+}
+
+bool Lexer::isIdentStart(int c)
+{
+ return (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other))
+ || c == '$' || c == '_';
+}
+
+bool Lexer::isIdentPart(int c)
+{
+ return (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other
+ | Mark_NonSpacing | Mark_SpacingCombining | Number_DecimalDigit | Punctuation_Connector))
+ || c == '$' || c == '_';
+}
+
+static bool isDecimalDigit(int c)
+{
+ return (c >= '0' && c <= '9');
+}
+
+bool Lexer::isHexDigit(int c)
+{
+ return (c >= '0' && c <= '9' ||
+ c >= 'a' && c <= 'f' ||
+ c >= 'A' && c <= 'F');
+}
+
+bool Lexer::isOctalDigit(int c)
+{
+ return (c >= '0' && c <= '7');
+}
+
+int Lexer::matchPunctuator(int c1, int c2, int c3, int c4)
+{
+ if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
+ shift(4);
+ return URSHIFTEQUAL;
+ } else if (c1 == '=' && c2 == '=' && c3 == '=') {
+ shift(3);
+ return STREQ;
+ } else if (c1 == '!' && c2 == '=' && c3 == '=') {
+ shift(3);
+ return STRNEQ;
+ } else if (c1 == '>' && c2 == '>' && c3 == '>') {
+ shift(3);
+ return URSHIFT;
+ } else if (c1 == '<' && c2 == '<' && c3 == '=') {
+ shift(3);
+ return LSHIFTEQUAL;
+ } else if (c1 == '>' && c2 == '>' && c3 == '=') {
+ shift(3);
+ return RSHIFTEQUAL;
+ } else if (c1 == '<' && c2 == '=') {
+ shift(2);
+ return LE;
+ } else if (c1 == '>' && c2 == '=') {
+ shift(2);
+ return GE;
+ } else if (c1 == '!' && c2 == '=') {
+ shift(2);
+ return NE;
+ } else if (c1 == '+' && c2 == '+') {
+ shift(2);
+ if (terminator)
+ return AUTOPLUSPLUS;
+ else
+ return PLUSPLUS;
+ } else if (c1 == '-' && c2 == '-') {
+ shift(2);
+ if (terminator)
+ return AUTOMINUSMINUS;
+ else
+ return MINUSMINUS;
+ } else if (c1 == '=' && c2 == '=') {
+ shift(2);
+ return EQEQ;
+ } else if (c1 == '+' && c2 == '=') {
+ shift(2);
+ return PLUSEQUAL;
+ } else if (c1 == '-' && c2 == '=') {
+ shift(2);
+ return MINUSEQUAL;
+ } else if (c1 == '*' && c2 == '=') {
+ shift(2);
+ return MULTEQUAL;
+ } else if (c1 == '/' && c2 == '=') {
+ shift(2);
+ return DIVEQUAL;
+ } else if (c1 == '&' && c2 == '=') {
+ shift(2);
+ return ANDEQUAL;
+ } else if (c1 == '^' && c2 == '=') {
+ shift(2);
+ return XOREQUAL;
+ } else if (c1 == '%' && c2 == '=') {
+ shift(2);
+ return MODEQUAL;
+ } else if (c1 == '|' && c2 == '=') {
+ shift(2);
+ return OREQUAL;
+ } else if (c1 == '<' && c2 == '<') {
+ shift(2);
+ return LSHIFT;
+ } else if (c1 == '>' && c2 == '>') {
+ shift(2);
+ return RSHIFT;
+ } else if (c1 == '&' && c2 == '&') {
+ shift(2);
+ return AND;
+ } else if (c1 == '|' && c2 == '|') {
+ shift(2);
+ return OR;
+ }
+
+ switch(c1) {
+ case '=':
+ case '>':
+ case '<':
+ case ',':
+ case '!':
+ case '~':
+ case '?':
+ case ':':
+ case '.':
+ case '+':
+ case '-':
+ case '*':
+ case '/':
+ case '&':
+ case '|':
+ case '^':
+ case '%':
+ case '(':
+ case ')':
+ case '{':
+ case '}':
+ case '[':
+ case ']':
+ case ';':
+ shift(1);
+ return static_cast<int>(c1);
+ default:
+ return -1;
+ }
+}
+
+unsigned short Lexer::singleEscape(unsigned short c)
+{
+ switch(c) {
+ case 'b':
+ return 0x08;
+ case 't':
+ return 0x09;
+ case 'n':
+ return 0x0A;
+ case 'v':
+ return 0x0B;
+ case 'f':
+ return 0x0C;
+ case 'r':
+ return 0x0D;
+ case '"':
+ return 0x22;
+ case '\'':
+ return 0x27;
+ case '\\':
+ return 0x5C;
+ default:
+ return c;
+ }
+}
+
+unsigned short Lexer::convertOctal(int c1, int c2, int c3)
+{
+ return static_cast<unsigned short>((c1 - '0') * 64 + (c2 - '0') * 8 + c3 - '0');
+}
+
+unsigned char Lexer::convertHex(int c)
+{
+ if (c >= '0' && c <= '9')
+ return static_cast<unsigned char>(c - '0');
+ if (c >= 'a' && c <= 'f')
+ return static_cast<unsigned char>(c - 'a' + 10);
+ return static_cast<unsigned char>(c - 'A' + 10);
+}
+
+unsigned char Lexer::convertHex(int c1, int c2)
+{
+ return ((convertHex(c1) << 4) + convertHex(c2));
+}
+
+KJS::UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4)
+{
+ return KJS::UChar((convertHex(c1) << 4) + convertHex(c2),
+ (convertHex(c3) << 4) + convertHex(c4));
+}
+
+void Lexer::record8(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c <= 0xff);
+ m_buffer8.append(static_cast<char>(c));
+}
+
+void Lexer::record16(int c)
+{
+ ASSERT(c >= 0);
+ ASSERT(c <= USHRT_MAX);
+ record16(UChar(static_cast<unsigned short>(c)));
+}
+
+void Lexer::record16(KJS::UChar c)
+{
+ m_buffer16.append(c);
+}
+
+bool Lexer::scanRegExp()
+{
+ m_buffer16.clear();
+ bool lastWasEscape = false;
+ bool inBrackets = false;
+
+ while (1) {
+ if (isLineTerminator() || current == -1)
+ return false;
+ else if (current != '/' || lastWasEscape == true || inBrackets == true)
+ {
+ // keep track of '[' and ']'
+ if (!lastWasEscape) {
+ if ( current == '[' && !inBrackets )
+ inBrackets = true;
+ if ( current == ']' && inBrackets )
+ inBrackets = false;
+ }
+ record16(current);
+ lastWasEscape =
+ !lastWasEscape && (current == '\\');
+ } else { // end of regexp
+ m_pattern = UString(m_buffer16);
+ m_buffer16.clear();
+ shift(1);
+ break;
+ }
+ shift(1);
+ }
+
+ while (isIdentPart(current)) {
+ record16(current);
+ shift(1);
+ }
+ m_flags = UString(m_buffer16);
+
+ return true;
+}
+
+void Lexer::clear()
+{
+ deleteAllValues(m_strings);
+ Vector<UString*> newStrings;
+ newStrings.reserveCapacity(initialStringTableCapacity);
+ m_strings.swap(newStrings);
+
+ deleteAllValues(m_identifiers);
+ Vector<KJS::Identifier*> newIdentifiers;
+ newIdentifiers.reserveCapacity(initialStringTableCapacity);
+ m_identifiers.swap(newIdentifiers);
+
+ Vector<char> newBuffer8;
+ newBuffer8.reserveCapacity(initialReadBufferCapacity);
+ m_buffer8.swap(newBuffer8);
+
+ Vector<UChar> newBuffer16;
+ newBuffer16.reserveCapacity(initialReadBufferCapacity);
+ m_buffer16.swap(newBuffer16);
+
+ m_pattern = 0;
+ m_flags = 0;
+}
+
+Identifier* Lexer::makeIdentifier(const Vector<KJS::UChar>& buffer)
+{
+ KJS::Identifier* identifier = new KJS::Identifier(buffer.data(), buffer.size());
+ m_identifiers.append(identifier);
+ return identifier;
+}
+
+UString* Lexer::makeUString(const Vector<KJS::UChar>& buffer)
+{
+ UString* string = new UString(buffer);
+ m_strings.append(string);
+ return string;
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/lexer.h b/JavaScriptCore/kjs/lexer.h
new file mode 100644
index 0000000..1ce27af
--- /dev/null
+++ b/JavaScriptCore/kjs/lexer.h
@@ -0,0 +1,149 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 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.
+ *
+ */
+
+#ifndef Lexer_h
+#define Lexer_h
+
+#include "ustring.h"
+#include <wtf/Vector.h>
+
+namespace KJS {
+
+ class Identifier;
+ class RegExp;
+
+ class Lexer : Noncopyable {
+ public:
+ void setCode(int startingLineNumber, const UChar *c, unsigned int len);
+ int lex();
+
+ int lineNo() const { return yylineno; }
+
+ bool prevTerminator() const { return terminator; }
+
+ enum State { Start,
+ IdentifierOrKeyword,
+ Identifier,
+ InIdentifierOrKeyword,
+ InIdentifier,
+ InIdentifierStartUnicodeEscapeStart,
+ InIdentifierStartUnicodeEscape,
+ InIdentifierPartUnicodeEscapeStart,
+ InIdentifierPartUnicodeEscape,
+ InSingleLineComment,
+ InMultiLineComment,
+ InNum,
+ InNum0,
+ InHex,
+ InOctal,
+ InDecimal,
+ InExponentIndicator,
+ InExponent,
+ Hex,
+ Octal,
+ Number,
+ String,
+ Eof,
+ InString,
+ InEscapeSequence,
+ InHexEscape,
+ InUnicodeEscape,
+ Other,
+ Bad };
+
+ bool scanRegExp();
+ const UString& pattern() const { return m_pattern; }
+ const UString& flags() const { return m_flags; }
+
+ static unsigned char convertHex(int);
+ static unsigned char convertHex(int c1, int c2);
+ static UChar convertUnicode(int c1, int c2, int c3, int c4);
+ static bool isIdentStart(int);
+ static bool isIdentPart(int);
+ static bool isHexDigit(int);
+
+ bool sawError() const { return error; }
+
+ void clear();
+
+ private:
+ friend Lexer& lexer();
+ Lexer();
+
+ int yylineno;
+ bool done;
+ Vector<char> m_buffer8;
+ Vector<UChar> m_buffer16;
+ bool terminator;
+ bool restrKeyword;
+ // encountered delimiter like "'" and "}" on last run
+ bool delimited;
+ bool skipLF;
+ bool skipCR;
+ bool eatNextIdentifier;
+ int stackToken;
+ int lastToken;
+
+ State state;
+ void setDone(State);
+ unsigned int pos;
+ void shift(unsigned int p);
+ void nextLine();
+ int lookupKeyword(const char *);
+
+ bool isWhiteSpace() const;
+ bool isLineTerminator();
+ static bool isOctalDigit(int);
+
+ int matchPunctuator(int c1, int c2, int c3, int c4);
+ static unsigned short singleEscape(unsigned short);
+ static unsigned short convertOctal(int c1, int c2, int c3);
+
+ void record8(int);
+ void record16(int);
+ void record16(UChar);
+
+ KJS::Identifier* makeIdentifier(const Vector<UChar>& buffer);
+ UString* makeUString(const Vector<UChar>& buffer);
+
+ const UChar* code;
+ unsigned int length;
+ int yycolumn;
+ int atLineStart;
+ bool error;
+
+ // current and following unicode characters (int to allow for -1 for end-of-file marker)
+ int current, next1, next2, next3;
+
+ Vector<UString*> m_strings;
+ Vector<KJS::Identifier*> m_identifiers;
+
+ UString m_pattern;
+ UString m_flags;
+ };
+
+ Lexer& lexer(); // Returns the singletone JavaScript lexer.
+
+} // namespace KJS
+
+#endif // Lexer_h
diff --git a/JavaScriptCore/kjs/list.cpp b/JavaScriptCore/kjs/list.cpp
new file mode 100644
index 0000000..5cc7cc2
--- /dev/null
+++ b/JavaScriptCore/kjs/list.cpp
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#include "config.h"
+#include "list.h"
+
+using std::min;
+
+namespace KJS {
+
+void List::getSlice(int startIndex, List& result) const
+{
+ const_iterator start = min(begin() + startIndex, end());
+ result.m_vector.appendRange(start, end());
+}
+
+List::ListSet& List::markSet()
+{
+ static ListSet staticMarkSet;
+ return staticMarkSet;
+}
+
+void List::markProtectedListsSlowCase()
+{
+ ListSet::iterator end = markSet().end();
+ for (ListSet::iterator it = markSet().begin(); it != end; ++it) {
+ List* list = *it;
+
+ iterator end2 = list->end();
+ for (iterator it2 = list->begin(); it2 != end2; ++it2) {
+ JSValue* v = *it2;
+ if (!v->marked())
+ v->mark();
+ }
+ }
+}
+
+void List::expandAndAppend(JSValue* v)
+{
+ ASSERT(m_vector.size() == m_vector.capacity());
+
+ // 4x growth would be excessive for a normal vector, but it's OK for Lists
+ // because they're short-lived.
+ m_vector.reserveCapacity(m_vector.capacity() * 4);
+
+ // As long as our size stays within our Vector's inline
+ // capacity, all our values are allocated on the stack, and
+ // therefore don't need explicit marking. Once our size exceeds
+ // our Vector's inline capacity, though, our values move to the
+ // heap, where they do need explicit marking.
+ if (!m_isInMarkSet) {
+ markSet().add(this);
+ m_isInMarkSet = true;
+ }
+
+ m_vector.uncheckedAppend(v);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/list.h b/JavaScriptCore/kjs/list.h
new file mode 100644
index 0000000..6a43e08
--- /dev/null
+++ b/JavaScriptCore/kjs/list.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2007 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_LIST_H
+#define KJS_LIST_H
+
+#include <kjs/value.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/Vector.h>
+
+namespace KJS {
+
+ class JSValue;
+ class List;
+
+ class List : Noncopyable {
+ private:
+ typedef Vector<JSValue*, 8> VectorType;
+ typedef HashSet<List*> ListSet;
+
+ public:
+ typedef VectorType::iterator iterator;
+ typedef VectorType::const_iterator const_iterator;
+
+ List()
+ : m_isInMarkSet(false)
+ {
+ }
+
+ ~List()
+ {
+ if (m_isInMarkSet)
+ markSet().remove(this);
+ }
+
+ size_t size() const { return m_vector.size(); }
+ bool isEmpty() const { return m_vector.isEmpty(); }
+
+ JSValue* at(size_t i) const
+ {
+ if (i < m_vector.size())
+ return m_vector.at(i);
+ return jsUndefined();
+ }
+
+ JSValue* operator[](int i) const { return at(i); }
+
+ void clear() { m_vector.clear(); }
+
+ void append(JSValue* v)
+ {
+ if (m_vector.size() < m_vector.capacity())
+ m_vector.uncheckedAppend(v);
+ else
+ // Putting the slow "expand and append" case all in one
+ // function measurably improves the performance of the fast
+ // "just append" case.
+ expandAndAppend(v);
+ }
+
+ void getSlice(int startIndex, List& result) const;
+
+ iterator begin() { return m_vector.begin(); }
+ iterator end() { return m_vector.end(); }
+
+ const_iterator begin() const { return m_vector.begin(); }
+ const_iterator end() const { return m_vector.end(); }
+
+ static void markProtectedLists()
+ {
+ if (!markSet().size())
+ return;
+ markProtectedListsSlowCase();
+ }
+
+ private:
+ static ListSet& markSet();
+ static void markProtectedListsSlowCase();
+
+ void expandAndAppend(JSValue*);
+
+ VectorType m_vector;
+ bool m_isInMarkSet;
+
+ private:
+ // Prohibits new / delete, which would break GC.
+ void* operator new(size_t);
+ void operator delete(void*);
+
+ void* operator new[](size_t);
+ void operator delete[](void*);
+
+ void* operator new(size_t, void*);
+ void operator delete(void*, size_t);
+ };
+
+} // namespace KJS
+
+#endif // KJS_LIST_H
diff --git a/JavaScriptCore/kjs/lookup.cpp b/JavaScriptCore/kjs/lookup.cpp
new file mode 100644
index 0000000..95dc5cb
--- /dev/null
+++ b/JavaScriptCore/kjs/lookup.cpp
@@ -0,0 +1,81 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * 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 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 <wtf/Assertions.h>
+
+namespace KJS {
+
+static inline bool keysMatch(const UChar* c, unsigned len, const char* s)
+{
+ // FIXME: This can run off the end of |s| if |c| has a U+0000 character in it.
+ const char* end = s + len;
+ for (; s != end; c++, s++)
+ if (c->uc != *s)
+ return false;
+ return *s == 0;
+}
+
+static inline const HashEntry* findEntry(const struct HashTable* table, unsigned int hash,
+ const UChar* c, unsigned int len)
+{
+ ASSERT(table->type == 3);
+
+ const HashEntry* e = &table->entries[hash & table->hashSizeMask];
+
+ if (!e->s)
+ return 0;
+
+ do {
+ // compare strings
+ if (keysMatch(c, len, e->s))
+ return e;
+
+ // try next bucket
+ e = e->next;
+ } while (e);
+ return 0;
+}
+
+const HashEntry* Lookup::findEntry(const struct HashTable* table, const Identifier& s)
+{
+ return KJS::findEntry(table, s.ustring().rep()->computedHash(), s.data(), s.size());
+}
+
+int Lookup::find(const struct HashTable *table, const UChar *c, unsigned int len)
+{
+ const HashEntry *entry = KJS::findEntry(table, UString::Rep::computeHash(c, len), c, len);
+ if (entry)
+ return entry->value.intValue;
+ return -1;
+}
+
+int Lookup::find(const struct HashTable* table, const Identifier& s)
+{
+ const HashEntry* entry = KJS::findEntry(table, s.ustring().rep()->computedHash(), s.data(), s.size());
+ if (entry)
+ return entry->value.intValue;
+ return -1;
+}
+
+}
diff --git a/JavaScriptCore/kjs/lookup.h b/JavaScriptCore/kjs/lookup.h
new file mode 100644
index 0000000..d477f88
--- /dev/null
+++ b/JavaScriptCore/kjs/lookup.h
@@ -0,0 +1,340 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 KJS_lookup_h
+#define KJS_lookup_h
+
+#include "ExecState.h"
+#include "function.h"
+#include "identifier.h"
+#include "JSGlobalObject.h"
+#include "object.h"
+#include <stdio.h>
+#include <wtf/Assertions.h>
+
+namespace KJS {
+
+ /**
+ * An entry in a hash table.
+ */
+ struct HashEntry {
+ /**
+ * s is the key (e.g. a property name)
+ */
+ const char* s;
+
+ /**
+ * value is the result value (enum value for properties and a function pointer to a constructor factory for functions)
+ */
+ union {
+ intptr_t intValue;
+ PrototypeFunction::JSMemberFunction functionValue;
+ } value;
+
+ /**
+ * attr is a set for flags (e.g. the property flags, see object.h)
+ */
+ unsigned char attr;
+ /**
+ * params is another number. For property hashtables, it is used to
+ * denote the number of argument of the function
+ */
+ short int params;
+ /**
+ * next is the pointer to the next entry for the same hash value
+ */
+ const HashEntry* next;
+ };
+
+ /**
+ * A hash table
+ * Usually the hashtable is generated by the create_hash_table script, from a .table file.
+ *
+ * The implementation uses an array of entries, "size" is the total size of that array.
+ * The entries between 0 and hashSize-1 are the entry points
+ * for each hash value, and the entries between hashSize and size-1
+ * are the overflow entries for the hash values that need one.
+ * The "next" pointer of the entry links entry points to overflow entries,
+ * and links overflow entries between them.
+ */
+ struct HashTable {
+ /**
+ * type is a version number. Currently always 2
+ */
+ int type;
+ /**
+ * size is the total number of entries in the hashtable, including the null entries,
+ * i.e. the size of the "entries" array.
+ * Used to iterate over all entries in the table
+ */
+ int size;
+ /**
+ * pointer to the array of entries
+ * Mind that some entries in the array are null (0,0,0,0).
+ */
+ const HashEntry* entries;
+ /**
+ * the maximum value for the hash minus 1. Always smaller than size.
+ */
+ int hashSizeMask;
+ };
+
+ /**
+ * @short Fast keyword lookup.
+ */
+ class Lookup {
+ public:
+ /**
+ * Find an entry in the table, and return its value (i.e. the value field of HashEntry)
+ */
+ static int find(const struct HashTable*, const Identifier&);
+ static int find(const struct HashTable*, const UChar*, unsigned int len);
+
+ /**
+ * Find an entry in the table, and return the entry
+ * This variant gives access to the other attributes of the entry,
+ * especially the attr field.
+ */
+ static const HashEntry* findEntry(const struct HashTable*, const Identifier&);
+
+ };
+
+ class ExecState;
+ class UString;
+ /**
+ * @internal
+ * Helper for getStaticFunctionSlot and getStaticPropertySlot
+ */
+ inline JSValue* staticFunctionGetter(ExecState* exec, JSObject*, const Identifier& propertyName, const PropertySlot& slot)
+ {
+ // Look for cached value in dynamic map of properties (in JSObject)
+ JSObject* thisObj = slot.slotBase();
+ JSValue* cachedVal = thisObj->getDirect(propertyName);
+ if (cachedVal)
+ return cachedVal;
+
+ const HashEntry* entry = slot.staticEntry();
+ JSValue* val = new PrototypeFunction(exec, entry->params, propertyName, entry->value.functionValue);
+ thisObj->putDirect(propertyName, val, entry->attr);
+ return val;
+ }
+
+ /**
+ * @internal
+ * Helper for getStaticValueSlot and getStaticPropertySlot
+ */
+ template <class ThisImp>
+ inline JSValue* staticValueGetter(ExecState* exec, JSObject*, const Identifier&, const PropertySlot& slot)
+ {
+ ThisImp* thisObj = static_cast<ThisImp*>(slot.slotBase());
+ const HashEntry* entry = slot.staticEntry();
+ return thisObj->getValueProperty(exec, entry->value.intValue);
+ }
+
+ /**
+ * Helper method for property lookups
+ *
+ * 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 arguments:
+ * @param FuncImp the class which implements this object's functions
+ * @param ThisImp the class of "this". It must implement the getValueProperty(exec,token) method,
+ * for non-function properties.
+ * @param ParentImp the class of the parent, to propagate the lookup.
+ *
+ * Method arguments:
+ * @param exec execution state, as usual
+ * @param propertyName the property we're looking for
+ * @param table the static hashtable for this class
+ * @param thisObj "this"
+ */
+ template <class ThisImp, class ParentImp>
+ inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table,
+ ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ {
+ const HashEntry* entry = Lookup::findEntry(table, propertyName);
+
+ if (!entry) // not found, forward to parent
+ return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
+
+ if (entry->attr & Function)
+ slot.setStaticEntry(thisObj, entry, staticFunctionGetter);
+ else
+ slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
+
+ 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)
+ {
+ const HashEntry* entry = Lookup::findEntry(table, propertyName);
+
+ if (!entry) // not found, forward to parent
+ return static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
+
+ ASSERT(entry->attr & Function);
+
+ slot.setStaticEntry(thisObj, entry, staticFunctionGetter);
+ return true;
+ }
+
+ /**
+ * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
+ * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
+ */
+ template <class ThisImp, class ParentImp>
+ inline bool getStaticValueSlot(ExecState* exec, const HashTable* table,
+ ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ {
+ const HashEntry* entry = Lookup::findEntry(table, propertyName);
+
+ if (!entry) // not found, forward to parent
+ return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
+
+ ASSERT(!(entry->attr & Function));
+
+ slot.setStaticEntry(thisObj, entry, staticValueGetter<ThisImp>);
+ return true;
+ }
+
+ /**
+ * This one is for "put".
+ * It looks up a hash entry for the property to be set. If an entry
+ * is found it sets the value and returns true, else it returns false.
+ */
+ template <class ThisImp>
+ inline bool lookupPut(ExecState* exec, const Identifier& propertyName,
+ JSValue* value, const HashTable* table, ThisImp* thisObj)
+ {
+ const HashEntry* entry = Lookup::findEntry(table, propertyName);
+
+ if (!entry)
+ return false;
+
+ if (entry->attr & Function) // function: put as override property
+ thisObj->putDirect(propertyName, value);
+ else if (!(entry->attr & ReadOnly))
+ thisObj->putValueProperty(exec, entry->value.intValue, value);
+
+ return true;
+ }
+
+ /**
+ * This one is for "put".
+ * It calls lookupPut<ThisImp>() to set the value. If that call
+ * returns false (meaning no entry in the hash table was found),
+ * then it calls put() on the ParentImp class.
+ */
+ template <class ThisImp, class ParentImp>
+ inline void lookupPut(ExecState* exec, const Identifier& propertyName,
+ JSValue* value, const HashTable* table, ThisImp* thisObj)
+ {
+ if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
+ thisObj->ParentImp::put(exec, propertyName, value); // not found: forward to parent
+ }
+
+ /**
+ * This template method retrieves or create an object that is unique
+ * (for a given global object) The first time this is called (for a given
+ * property name), the Object will be constructed, and set as a property
+ * of the global object. Later calls will simply retrieve that cached object.
+ * Note that the object constructor must take 1 argument, exec.
+ */
+ template <class ClassCtor>
+ inline JSObject* cacheGlobalObject(ExecState* exec, const Identifier& propertyName)
+ {
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ JSValue* obj = globalObject->getDirect(propertyName);
+ if (obj) {
+ ASSERT(obj->isObject());
+ return static_cast<JSObject* >(obj);
+ }
+ JSObject* newObject = new ClassCtor(exec);
+ globalObject->putDirect(propertyName, newObject, DontEnum);
+ return newObject;
+ }
+
+} // namespace
+
+/**
+ * Helpers to define prototype objects (each of which simply implements
+ * the functions for a type of objects).
+ * Sorry for this not being very readable, but it actually saves much copy-n-paste.
+ * ParentPrototype is not our base class, it's the object we use as fallback.
+ * The reason for this is that there should only be ONE DOMNode.hasAttributes (e.g.),
+ * not one in each derived class. So we link the (unique) prototypes between them.
+ *
+ * Using those macros is very simple: define the hashtable (e.g. "DOMNodePrototypeTable"), then
+ * KJS_DEFINE_PROTOTYPE(DOMNodePrototype)
+ * KJS_IMPLEMENT_PROTOTYPE("DOMNode", DOMNodePrototype, DOMNodePrototypeFunction)
+ * and use DOMNodePrototype::self(exec) as prototype in the DOMNode constructor.
+ * If the prototype has a "parent prototype", e.g. DOMElementPrototype falls back on DOMNodePrototype,
+ * then the first line will use KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE, with DOMNodePrototype as the second argument.
+ */
+
+// These macros assume that a prototype's only properties are functions
+#define KJS_DEFINE_PROTOTYPE(ClassPrototype) \
+ class ClassPrototype : public KJS::JSObject { \
+ public: \
+ static KJS::JSObject* self(KJS::ExecState* exec); \
+ virtual const KJS::ClassInfo* classInfo() const { return &info; } \
+ static const KJS::ClassInfo info; \
+ bool getOwnPropertySlot(KJS::ExecState* , const KJS::Identifier&, KJS::PropertySlot&); \
+ ClassPrototype(KJS::ExecState* exec) \
+ : KJS::JSObject(exec->lexicalGlobalObject()->objectPrototype()) { } \
+ \
+ };
+
+#define KJS_DEFINE_PROTOTYPE_WITH_PROTOTYPE(ClassPrototype, ClassPrototypePrototype) \
+ class ClassPrototype : public KJS::JSObject { \
+ public: \
+ static KJS::JSObject* self(KJS::ExecState* exec); \
+ virtual const KJS::ClassInfo* classInfo() const { return &info; } \
+ static const KJS::ClassInfo info; \
+ bool getOwnPropertySlot(KJS::ExecState*, const KJS::Identifier&, KJS::PropertySlot&); \
+ ClassPrototype(KJS::ExecState* exec) \
+ : KJS::JSObject(ClassPrototypePrototype::self(exec)) { } \
+ \
+ };
+
+#define KJS_IMPLEMENT_PROTOTYPE(ClassName, ClassPrototype) \
+ const ClassInfo ClassPrototype::info = { ClassName"Prototype", 0, &ClassPrototype##Table }; \
+ JSObject* ClassPrototype::self(ExecState* exec) \
+ { \
+ static Identifier* prototypeIdentifier = new Identifier("[[" ClassName ".prototype]]"); \
+ return KJS::cacheGlobalObject<ClassPrototype>(exec, *prototypeIdentifier); \
+ } \
+ bool ClassPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) \
+ { \
+ return getStaticFunctionSlot<JSObject>(exec, &ClassPrototype##Table, this, propertyName, slot); \
+ }
+
+#endif // KJS_lookup_h
diff --git a/JavaScriptCore/kjs/math_object.cpp b/JavaScriptCore/kjs/math_object.cpp
new file mode 100644
index 0000000..805efda
--- /dev/null
+++ b/JavaScriptCore/kjs/math_object.cpp
@@ -0,0 +1,243 @@
+/*
+ * 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 "math_object.h"
+#include "math_object.lut.h"
+
+#include "operations.h"
+#include <time.h>
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+
+namespace KJS {
+
+// ------------------------------ MathObjectImp --------------------------------
+
+const ClassInfo MathObjectImp::info = { "Math", 0, &mathTable };
+
+/* Source for math_object.lut.h
+@begin mathTable 21
+ E MathObjectImp::Euler DontEnum|DontDelete|ReadOnly
+ LN2 MathObjectImp::Ln2 DontEnum|DontDelete|ReadOnly
+ LN10 MathObjectImp::Ln10 DontEnum|DontDelete|ReadOnly
+ LOG2E MathObjectImp::Log2E DontEnum|DontDelete|ReadOnly
+ LOG10E MathObjectImp::Log10E DontEnum|DontDelete|ReadOnly
+ PI MathObjectImp::Pi DontEnum|DontDelete|ReadOnly
+ SQRT1_2 MathObjectImp::Sqrt1_2 DontEnum|DontDelete|ReadOnly
+ SQRT2 MathObjectImp::Sqrt2 DontEnum|DontDelete|ReadOnly
+ 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
+*/
+
+MathObjectImp::MathObjectImp(ExecState*, ObjectPrototype* objectPrototype)
+ : JSObject(objectPrototype)
+{
+}
+
+// ECMA 15.8
+
+bool MathObjectImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticPropertySlot<MathObjectImp, JSObject>(exec, &mathTable, this, propertyName, slot);
+}
+
+JSValue* MathObjectImp::getValueProperty(ExecState*, int token) const
+{
+ switch (token) {
+ case Euler:
+ return jsNumber(exp(1.0));
+ case Ln2:
+ return jsNumber(log(2.0));
+ case Ln10:
+ return jsNumber(log(10.0));
+ case Log2E:
+ return jsNumber(1.0 / log(2.0));
+ case Log10E:
+ return jsNumber(1.0 / log(10.0));
+ case Pi:
+ return jsNumber(piDouble);
+ case Sqrt1_2:
+ return jsNumber(sqrt(0.5));
+ case Sqrt2:
+ return jsNumber(sqrt(2.0));
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+// ------------------------------ Functions --------------------------------
+
+JSValue* mathProtoFuncAbs(ExecState* exec, JSObject*, const List& args)
+{
+ double arg = args[0]->toNumber(exec);
+ return signbit(arg) ? jsNumber(-arg) : jsNumber(arg);
+}
+
+JSValue* mathProtoFuncACos(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(acos(args[0]->toNumber(exec)));
+}
+
+JSValue* mathProtoFuncASin(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(asin(args[0]->toNumber(exec)));
+}
+
+JSValue* mathProtoFuncATan(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(atan(args[0]->toNumber(exec)));
+}
+
+JSValue* mathProtoFuncATan2(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(atan2(args[0]->toNumber(exec), args[1]->toNumber(exec)));
+}
+
+JSValue* mathProtoFuncCeil(ExecState* exec, JSObject*, const List& args)
+{
+ double arg = args[0]->toNumber(exec);
+ if (signbit(arg) && arg > -1.0)
+ return jsNumber(-0.0);
+ return jsNumber(ceil(arg));
+}
+
+JSValue* mathProtoFuncCos(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(cos(args[0]->toNumber(exec)));
+}
+
+JSValue* mathProtoFuncExp(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(exp(args[0]->toNumber(exec)));
+}
+
+JSValue* mathProtoFuncFloor(ExecState* exec, JSObject*, const List& args)
+{
+ double arg = args[0]->toNumber(exec);
+ if (signbit(arg) && arg == 0.0)
+ return jsNumber(-0.0);
+ return jsNumber(floor(arg));
+}
+
+JSValue* mathProtoFuncLog(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(log(args[0]->toNumber(exec)));
+}
+
+JSValue* mathProtoFuncMax(ExecState* exec, JSObject*, const List& args)
+{
+ unsigned argsCount = args.size();
+ double result = -Inf;
+ for (unsigned k = 0; k < argsCount; ++k) {
+ double val = args[k]->toNumber(exec);
+ if (isnan(val)) {
+ result = NaN;
+ break;
+ }
+ if (val > result || (val == 0 && result == 0 && !signbit(val)))
+ result = val;
+ }
+ return jsNumber(result);
+}
+
+JSValue* mathProtoFuncMin(ExecState* exec, JSObject*, const List& args)
+{
+ unsigned argsCount = args.size();
+ double result = +Inf;
+ for (unsigned k = 0; k < argsCount; ++k) {
+ double val = args[k]->toNumber(exec);
+ if (isnan(val)) {
+ result = NaN;
+ break;
+ }
+ if (val < result || (val == 0 && result == 0 && signbit(val)))
+ result = val;
+ }
+ return jsNumber(result);
+}
+
+JSValue* mathProtoFuncPow(ExecState* exec, JSObject*, const List& args)
+{
+ // ECMA 15.8.2.1.13
+
+ double arg = args[0]->toNumber(exec);
+ double arg2 = args[1]->toNumber(exec);
+
+ if (isnan(arg2))
+ return jsNumber(NaN);
+ if (isinf(arg2) && fabs(arg) == 1)
+ return jsNumber(NaN);
+ return jsNumber(pow(arg, arg2));
+}
+
+static bool didInitRandom;
+
+JSValue* mathProtoFuncRandom(ExecState*, JSObject*, const List&)
+{
+ if (!didInitRandom) {
+ wtf_random_init();
+ didInitRandom = true;
+ }
+ return jsNumber(wtf_random());
+}
+
+JSValue* mathProtoFuncRound(ExecState* exec, JSObject*, const List& args)
+{
+ double arg = args[0]->toNumber(exec);
+ if (signbit(arg) && arg >= -0.5)
+ return jsNumber(-0.0);
+ return jsNumber(floor(arg + 0.5));
+}
+
+JSValue* mathProtoFuncSin(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(sin(args[0]->toNumber(exec)));
+}
+
+JSValue* mathProtoFuncSqrt(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(sqrt(args[0]->toNumber(exec)));
+}
+
+JSValue* mathProtoFuncTan(ExecState* exec, JSObject*, const List& args)
+{
+ return jsNumber(tan(args[0]->toNumber(exec)));
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/math_object.h b/JavaScriptCore/kjs/math_object.h
new file mode 100644
index 0000000..72e442f
--- /dev/null
+++ b/JavaScriptCore/kjs/math_object.h
@@ -0,0 +1,65 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef MATH_OBJECT_H_
+#define MATH_OBJECT_H_
+
+#include "function_object.h"
+#include "lookup.h"
+
+namespace KJS {
+
+ class MathObjectImp : public JSObject {
+ public:
+ MathObjectImp(ExecState*, ObjectPrototype*);
+
+ bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ JSValue* getValueProperty(ExecState*, int token) const;
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+
+ enum { Euler, Ln2, Ln10, Log2E, Log10E, Pi, Sqrt1_2, Sqrt2 };
+ };
+
+ // Functions
+ JSValue* mathProtoFuncAbs(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncACos(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncASin(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncATan(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncATan2(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncCeil(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncCos(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncExp(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncFloor(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncLog(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncMax(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncMin(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncPow(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncRandom(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncRound(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncSin(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncSqrt(ExecState*, JSObject*, const List&);
+ JSValue* mathProtoFuncTan(ExecState*, JSObject*, const List&);
+
+} // namespace KJS
+
+#endif // MATH_OBJECT_H_
diff --git a/JavaScriptCore/kjs/nodes.cpp b/JavaScriptCore/kjs/nodes.cpp
new file mode 100644
index 0000000..b149d59
--- /dev/null
+++ b/JavaScriptCore/kjs/nodes.cpp
@@ -0,0 +1,4710 @@
+/*
+* Copyright (C) 1999-2002 Harri Porten (porten@kde.org)
+* Copyright (C) 2001 Peter Kelly (pmk@post.com)
+* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+* Copyright (C) 2007 Maks Orlovich
+* 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 "nodes.h"
+
+#include "ExecState.h"
+#include "JSGlobalObject.h"
+#include "Parser.h"
+#include "PropertyNameArray.h"
+#include "array_object.h"
+#include "debugger.h"
+#include "function_object.h"
+#include "lexer.h"
+#include "operations.h"
+#include "regexp_object.h"
+#include <math.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashCountedSet.h>
+#include <wtf/HashSet.h>
+#include <wtf/MathExtras.h>
+
+namespace KJS {
+
+class FunctionBodyNodeWithDebuggerHooks : public FunctionBodyNode {
+public:
+ FunctionBodyNodeWithDebuggerHooks(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+};
+
+#if COMPILER(GCC)
+#define UNLIKELY(x) \
+ __builtin_expect ((x), 0)
+#else
+#define UNLIKELY(x) x
+#endif
+
+#define KJS_CHECKEXCEPTION \
+if (UNLIKELY(exec->hadException())) \
+ return rethrowException(exec);
+
+#define KJS_CHECKEXCEPTIONVALUE \
+if (UNLIKELY(exec->hadException())) { \
+ handleException(exec); \
+ return jsUndefined(); \
+}
+
+#define KJS_CHECKEXCEPTIONNUMBER \
+if (UNLIKELY(exec->hadException())) { \
+ handleException(exec); \
+ return 0; \
+}
+
+#define KJS_CHECKEXCEPTIONBOOLEAN \
+if (UNLIKELY(exec->hadException())) { \
+ handleException(exec); \
+ return false; \
+}
+
+#define KJS_CHECKEXCEPTIONVOID \
+if (UNLIKELY(exec->hadException())) { \
+ handleException(exec); \
+ return; \
+}
+
+#if !ASSERT_DISABLED
+static inline bool canSkipLookup(ExecState* exec, const Identifier& ident)
+{
+ // Static lookup in EvalCode is impossible because variables aren't DontDelete.
+ // Static lookup in GlobalCode may be possible, but we haven't implemented support for it yet.
+ if (exec->codeType() != FunctionCode)
+ return false;
+
+ // Static lookup is impossible when something dynamic has been added to the front of the scope chain.
+ if (exec->variableObject() != exec->scopeChain().top())
+ return false;
+
+ // Static lookup is impossible if the symbol isn't statically declared.
+ if (!exec->variableObject()->symbolTable().contains(ident.ustring().rep()))
+ return false;
+
+ return true;
+}
+#endif
+
+static inline bool isConstant(const LocalStorage& localStorage, size_t index)
+{
+ ASSERT(index < localStorage.size());
+ return localStorage[index].attributes & ReadOnly;
+}
+
+// ------------------------------ Node -----------------------------------------
+
+#ifndef NDEBUG
+#ifndef LOG_CHANNEL_PREFIX
+#define LOG_CHANNEL_PREFIX Log
+#endif
+static WTFLogChannel LogKJSNodeLeaks = { 0x00000000, "", WTFLogChannelOn };
+
+struct ParserRefCountedCounter {
+ static unsigned count;
+ ParserRefCountedCounter()
+ {
+ if (count)
+ LOG(KJSNodeLeaks, "LEAK: %u KJS::Node\n", count);
+ }
+};
+unsigned ParserRefCountedCounter::count = 0;
+static ParserRefCountedCounter parserRefCountedCounter;
+#endif
+
+static HashSet<ParserRefCounted*>* newTrackedObjects;
+static HashCountedSet<ParserRefCounted*>* trackedObjectExtraRefCounts;
+
+ParserRefCounted::ParserRefCounted()
+{
+#ifndef NDEBUG
+ ++ParserRefCountedCounter::count;
+#endif
+ if (!newTrackedObjects)
+ newTrackedObjects = new HashSet<ParserRefCounted*>;
+ newTrackedObjects->add(this);
+ ASSERT(newTrackedObjects->contains(this));
+}
+
+ParserRefCounted::~ParserRefCounted()
+{
+#ifndef NDEBUG
+ --ParserRefCountedCounter::count;
+#endif
+}
+
+void ParserRefCounted::ref()
+{
+ // bumping from 0 to 1 is just removing from the new nodes set
+ if (newTrackedObjects) {
+ HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->find(this);
+ if (it != newTrackedObjects->end()) {
+ newTrackedObjects->remove(it);
+ ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
+ return;
+ }
+ }
+
+ ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
+
+ if (!trackedObjectExtraRefCounts)
+ trackedObjectExtraRefCounts = new HashCountedSet<ParserRefCounted*>;
+ trackedObjectExtraRefCounts->add(this);
+}
+
+void ParserRefCounted::deref()
+{
+ ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
+
+ if (!trackedObjectExtraRefCounts) {
+ delete this;
+ return;
+ }
+
+ HashCountedSet<ParserRefCounted*>::iterator it = trackedObjectExtraRefCounts->find(this);
+ if (it == trackedObjectExtraRefCounts->end())
+ delete this;
+ else
+ trackedObjectExtraRefCounts->remove(it);
+}
+
+unsigned ParserRefCounted::refcount()
+{
+ if (newTrackedObjects && newTrackedObjects->contains(this)) {
+ ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
+ return 0;
+ }
+
+ ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
+
+ if (!trackedObjectExtraRefCounts)
+ return 1;
+
+ return 1 + trackedObjectExtraRefCounts->count(this);
+}
+
+void ParserRefCounted::deleteNewObjects()
+{
+ if (!newTrackedObjects)
+ return;
+
+#ifndef NDEBUG
+ HashSet<ParserRefCounted*>::iterator end = newTrackedObjects->end();
+ for (HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->begin(); it != end; ++it)
+ ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(*it));
+#endif
+ deleteAllValues(*newTrackedObjects);
+ delete newTrackedObjects;
+ newTrackedObjects = 0;
+}
+
+Node::Node()
+ : m_expectedReturnType(ObjectType)
+{
+ m_line = lexer().lineNo();
+}
+
+Node::Node(JSType expectedReturn)
+ : m_expectedReturnType(expectedReturn)
+{
+ m_line = lexer().lineNo();
+}
+
+double ExpressionNode::evaluateToNumber(ExecState* exec)
+{
+ JSValue* value = evaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return value->toNumber(exec);
+}
+
+bool ExpressionNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* value = evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return value->toBoolean(exec);
+}
+
+int32_t ExpressionNode::evaluateToInt32(ExecState* exec)
+{
+ JSValue* value = evaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return value->toInt32(exec);
+}
+
+uint32_t ExpressionNode::evaluateToUInt32(ExecState* exec)
+{
+ JSValue* value = evaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return value->toUInt32(exec);
+}
+
+static void substitute(UString& string, const UString& substring) KJS_FAST_CALL;
+static void substitute(UString& string, const UString& substring)
+{
+ int position = string.find("%s");
+ ASSERT(position != -1);
+ UString newString = string.substr(0, position);
+ newString.append(substring);
+ newString.append(string.substr(position + 2));
+ string = newString;
+}
+
+static inline int currentSourceId(ExecState* exec) KJS_FAST_CALL;
+static inline int currentSourceId(ExecState* exec)
+{
+ return exec->scopeNode()->sourceId();
+}
+
+static inline const UString& currentSourceURL(ExecState* exec) KJS_FAST_CALL;
+static inline const UString& currentSourceURL(ExecState* exec)
+{
+ return exec->scopeNode()->sourceURL();
+}
+
+JSValue* Node::setErrorCompletion(ExecState* exec, ErrorType e, const char* msg)
+{
+ return exec->setThrowCompletion(Error::create(exec, e, msg, lineNo(), currentSourceId(exec), currentSourceURL(exec)));
+}
+
+JSValue* Node::setErrorCompletion(ExecState* exec, ErrorType e, const char* msg, const Identifier& ident)
+{
+ UString message = msg;
+ substitute(message, ident.ustring());
+ return exec->setThrowCompletion(Error::create(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec)));
+}
+
+JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg)
+{
+ return KJS::throwError(exec, e, msg, lineNo(), currentSourceId(exec), currentSourceURL(exec));
+}
+
+JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, const char* string)
+{
+ UString message = msg;
+ substitute(message, string);
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
+}
+
+JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, Node* expr)
+{
+ UString message = msg;
+ substitute(message, v->toString(exec));
+ substitute(message, expr->toString());
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
+}
+
+JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, const Identifier& label)
+{
+ UString message = msg;
+ substitute(message, label.ustring());
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
+}
+
+JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, Node* e1, Node* e2)
+{
+ UString message = msg;
+ substitute(message, v->toString(exec));
+ substitute(message, e1->toString());
+ substitute(message, e2->toString());
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
+}
+
+JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, Node* expr, const Identifier& label)
+{
+ UString message = msg;
+ substitute(message, v->toString(exec));
+ substitute(message, expr->toString());
+ substitute(message, label.ustring());
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
+}
+
+JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, const Identifier& label)
+{
+ UString message = msg;
+ substitute(message, v->toString(exec));
+ substitute(message, label.ustring());
+ return KJS::throwError(exec, e, message, lineNo(), currentSourceId(exec), currentSourceURL(exec));
+}
+
+JSValue* Node::throwUndefinedVariableError(ExecState* exec, const Identifier& ident)
+{
+ return throwError(exec, ReferenceError, "Can't find variable: %s", ident);
+}
+
+void Node::handleException(ExecState* exec)
+{
+ handleException(exec, exec->exception());
+}
+
+void Node::handleException(ExecState* exec, JSValue* exceptionValue)
+{
+ if (exceptionValue->isObject()) {
+ JSObject* exception = static_cast<JSObject*>(exceptionValue);
+ if (!exception->hasProperty(exec, "line") && !exception->hasProperty(exec, "sourceURL")) {
+ exception->put(exec, "line", jsNumber(m_line));
+ exception->put(exec, "sourceURL", jsString(currentSourceURL(exec)));
+ }
+ }
+ Debugger* dbg = exec->dynamicGlobalObject()->debugger();
+ if (dbg && !dbg->hasHandledException(exec, exceptionValue))
+ dbg->exception(exec, currentSourceId(exec), m_line, exceptionValue);
+}
+
+NEVER_INLINE JSValue* Node::rethrowException(ExecState* exec)
+{
+ JSValue* exception = exec->exception();
+ exec->clearException();
+ handleException(exec, exception);
+ return exec->setThrowCompletion(exception);
+}
+
+// ------------------------------ StatementNode --------------------------------
+
+StatementNode::StatementNode()
+ : m_lastLine(-1)
+{
+ m_line = -1;
+}
+
+void StatementNode::setLoc(int firstLine, int lastLine)
+{
+ m_line = firstLine;
+ m_lastLine = lastLine;
+}
+
+// ------------------------------ SourceElements --------------------------------
+
+void SourceElements::append(PassRefPtr<StatementNode> statement)
+{
+ if (statement->isEmptyStatement())
+ return;
+
+ if (Debugger::debuggersPresent)
+ m_statements.append(new BreakpointCheckStatement(statement));
+ else
+ m_statements.append(statement);
+}
+
+// ------------------------------ BreakpointCheckStatement --------------------------------
+
+BreakpointCheckStatement::BreakpointCheckStatement(PassRefPtr<StatementNode> statement)
+ : m_statement(statement)
+{
+ ASSERT(m_statement);
+}
+
+JSValue* BreakpointCheckStatement::execute(ExecState* exec)
+{
+ if (Debugger* debugger = exec->dynamicGlobalObject()->debugger())
+ if (!debugger->atStatement(exec, currentSourceId(exec), m_statement->firstLine(), m_statement->lastLine()))
+ return exec->setNormalCompletion();
+ return m_statement->execute(exec);
+}
+
+void BreakpointCheckStatement::streamTo(SourceStream& stream) const
+{
+ m_statement->streamTo(stream);
+}
+
+void BreakpointCheckStatement::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_statement.get());
+}
+
+// ------------------------------ NullNode -------------------------------------
+
+JSValue* NullNode::evaluate(ExecState* )
+{
+ return jsNull();
+}
+
+// ------------------------------ FalseNode ----------------------------------
+
+JSValue* FalseNode::evaluate(ExecState*)
+{
+ return jsBoolean(false);
+}
+
+// ------------------------------ TrueNode ----------------------------------
+
+JSValue* TrueNode::evaluate(ExecState*)
+{
+ return jsBoolean(true);
+}
+
+// ------------------------------ NumberNode -----------------------------------
+
+JSValue* NumberNode::evaluate(ExecState*)
+{
+ // Number nodes are only created when the number can't fit in a JSImmediate, so no need to check again.
+ return jsNumberCell(m_double);
+}
+
+double NumberNode::evaluateToNumber(ExecState*)
+{
+ return m_double;
+}
+
+bool NumberNode::evaluateToBoolean(ExecState*)
+{
+ return m_double < 0.0 || m_double > 0.0; // false for NaN as well as 0
+}
+
+int32_t NumberNode::evaluateToInt32(ExecState*)
+{
+ return JSValue::toInt32(m_double);
+}
+
+uint32_t NumberNode::evaluateToUInt32(ExecState*)
+{
+ return JSValue::toUInt32(m_double);
+}
+
+// ------------------------------ ImmediateNumberNode -----------------------------------
+
+JSValue* ImmediateNumberNode::evaluate(ExecState*)
+{
+ return m_value;
+}
+
+int32_t ImmediateNumberNode::evaluateToInt32(ExecState*)
+{
+ return JSImmediate::getTruncatedInt32(m_value);
+}
+
+uint32_t ImmediateNumberNode::evaluateToUInt32(ExecState*)
+{
+ uint32_t i;
+ if (JSImmediate::getTruncatedUInt32(m_value, i))
+ return i;
+ bool ok;
+ return JSValue::toUInt32SlowCase(m_double, ok);
+}
+
+// ------------------------------ StringNode -----------------------------------
+
+JSValue* StringNode::evaluate(ExecState*)
+{
+ return jsOwnedString(m_value);
+}
+
+double StringNode::evaluateToNumber(ExecState*)
+{
+ return m_value.toDouble();
+}
+
+bool StringNode::evaluateToBoolean(ExecState*)
+{
+ return !m_value.isEmpty();
+}
+
+// ------------------------------ RegExpNode -----------------------------------
+
+JSValue* RegExpNode::evaluate(ExecState* exec)
+{
+ return exec->lexicalGlobalObject()->regExpConstructor()->createRegExpImp(exec, m_regExp);
+}
+
+// ------------------------------ ThisNode -------------------------------------
+
+// ECMA 11.1.1
+JSValue* ThisNode::evaluate(ExecState* exec)
+{
+ return exec->thisValue();
+}
+
+// ------------------------------ ResolveNode ----------------------------------
+
+// ECMA 11.1.2 & 10.1.4
+JSValue* ResolveNode::inlineEvaluate(ExecState* exec)
+{
+ // Check for missed optimization opportunity.
+ ASSERT(!canSkipLookup(exec, m_ident));
+
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // we must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ do {
+ JSObject* o = *iter;
+
+ if (o->getPropertySlot(exec, m_ident, slot))
+ return slot.getValue(exec, o, m_ident);
+
+ ++iter;
+ } while (iter != end);
+
+ return throwUndefinedVariableError(exec, m_ident);
+}
+
+JSValue* ResolveNode::evaluate(ExecState* exec)
+{
+ return inlineEvaluate(exec);
+}
+
+double ResolveNode::evaluateToNumber(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toNumber(exec);
+}
+
+bool ResolveNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return v->toBoolean(exec);
+}
+
+int32_t ResolveNode::evaluateToInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toInt32(exec);
+}
+
+uint32_t ResolveNode::evaluateToUInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toUInt32(exec);
+}
+
+void ResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
+{
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker())
+ new (this) LocalVarAccessNode(index);
+}
+
+JSValue* LocalVarAccessNode::inlineEvaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+ return exec->localStorage()[m_index].value;
+}
+
+JSValue* LocalVarAccessNode::evaluate(ExecState* exec)
+{
+ return inlineEvaluate(exec);
+}
+
+double LocalVarAccessNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluate(exec)->toNumber(exec);
+}
+
+bool LocalVarAccessNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluate(exec)->toBoolean(exec);
+}
+
+int32_t LocalVarAccessNode::evaluateToInt32(ExecState* exec)
+{
+ return inlineEvaluate(exec)->toInt32(exec);
+}
+
+uint32_t LocalVarAccessNode::evaluateToUInt32(ExecState* exec)
+{
+ return inlineEvaluate(exec)->toUInt32(exec);
+}
+
+// ------------------------------ ElementNode ----------------------------------
+
+void ElementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_next)
+ nodeStack.append(m_next.get());
+ ASSERT(m_node);
+ nodeStack.append(m_node.get());
+}
+
+// ECMA 11.1.4
+JSValue* ElementNode::evaluate(ExecState* exec)
+{
+ JSObject* array = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList());
+ int length = 0;
+ for (ElementNode* n = this; n; n = n->m_next.get()) {
+ JSValue* val = n->m_node->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ length += n->m_elision;
+ array->put(exec, length++, val);
+ }
+ return array;
+}
+
+// ------------------------------ ArrayNode ------------------------------------
+
+void ArrayNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_element)
+ nodeStack.append(m_element.get());
+}
+
+// ECMA 11.1.4
+JSValue* ArrayNode::evaluate(ExecState* exec)
+{
+ JSObject* array;
+ int length;
+
+ if (m_element) {
+ array = static_cast<JSObject*>(m_element->evaluate(exec));
+ KJS_CHECKEXCEPTIONVALUE
+ length = m_optional ? array->get(exec, exec->propertyNames().length)->toInt32(exec) : 0;
+ } else {
+ JSValue* newArr = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, exec->emptyList());
+ array = static_cast<JSObject*>(newArr);
+ length = 0;
+ }
+
+ if (m_optional)
+ array->put(exec, exec->propertyNames().length, jsNumber(m_elision + length));
+
+ return array;
+}
+
+// ------------------------------ ObjectLiteralNode ----------------------------
+
+void ObjectLiteralNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_list)
+ nodeStack.append(m_list.get());
+}
+
+// ECMA 11.1.5
+JSValue* ObjectLiteralNode::evaluate(ExecState* exec)
+{
+ if (m_list)
+ return m_list->evaluate(exec);
+
+ return exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
+}
+
+// ------------------------------ PropertyListNode -----------------------------
+
+void PropertyListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_next)
+ nodeStack.append(m_next.get());
+ nodeStack.append(m_node.get());
+}
+
+// ECMA 11.1.5
+JSValue* PropertyListNode::evaluate(ExecState* exec)
+{
+ JSObject* obj = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
+
+ for (PropertyListNode* p = this; p; p = p->m_next.get()) {
+ JSValue* v = p->m_node->m_assign->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ switch (p->m_node->m_type) {
+ case PropertyNode::Getter:
+ ASSERT(v->isObject());
+ obj->defineGetter(exec, p->m_node->name(), static_cast<JSObject* >(v));
+ break;
+ case PropertyNode::Setter:
+ ASSERT(v->isObject());
+ obj->defineSetter(exec, p->m_node->name(), static_cast<JSObject* >(v));
+ break;
+ case PropertyNode::Constant:
+ obj->put(exec, p->m_node->name(), v);
+ break;
+ }
+ }
+
+ return obj;
+}
+
+// ------------------------------ PropertyNode -----------------------------
+
+void PropertyNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_assign.get());
+}
+
+// ECMA 11.1.5
+JSValue* PropertyNode::evaluate(ExecState*)
+{
+ ASSERT(false);
+ return jsNull();
+}
+
+// ------------------------------ BracketAccessorNode --------------------------------
+
+void BracketAccessorNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_subscript.get());
+ nodeStack.append(m_base.get());
+}
+
+// ECMA 11.2.1a
+JSValue* BracketAccessorNode::inlineEvaluate(ExecState* exec)
+{
+ JSValue* v1 = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* v2 = m_subscript->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSObject* o = v1->toObject(exec);
+ uint32_t i;
+ if (v2->getUInt32(i))
+ return o->get(exec, i);
+ return o->get(exec, Identifier(v2->toString(exec)));
+}
+
+JSValue* BracketAccessorNode::evaluate(ExecState* exec)
+{
+ return inlineEvaluate(exec);
+}
+
+double BracketAccessorNode::evaluateToNumber(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toNumber(exec);
+}
+
+bool BracketAccessorNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return v->toBoolean(exec);
+}
+
+int32_t BracketAccessorNode::evaluateToInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toInt32(exec);
+}
+
+uint32_t BracketAccessorNode::evaluateToUInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toUInt32(exec);
+}
+
+// ------------------------------ DotAccessorNode --------------------------------
+
+void DotAccessorNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_base.get());
+}
+
+// ECMA 11.2.1b
+JSValue* DotAccessorNode::inlineEvaluate(ExecState* exec)
+{
+ JSValue* v = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ return v->toObject(exec)->get(exec, m_ident);
+}
+
+JSValue* DotAccessorNode::evaluate(ExecState* exec)
+{
+ return inlineEvaluate(exec);
+}
+
+double DotAccessorNode::evaluateToNumber(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toNumber(exec);
+}
+
+bool DotAccessorNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return v->toBoolean(exec);
+}
+
+int32_t DotAccessorNode::evaluateToInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toInt32(exec);
+}
+
+uint32_t DotAccessorNode::evaluateToUInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toUInt32(exec);
+}
+
+// ------------------------------ ArgumentListNode -----------------------------
+
+void ArgumentListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_next)
+ nodeStack.append(m_next.get());
+ ASSERT(m_expr);
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 11.2.4
+void ArgumentListNode::evaluateList(ExecState* exec, List& list)
+{
+ for (ArgumentListNode* n = this; n; n = n->m_next.get()) {
+ JSValue* v = n->m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTIONVOID
+ list.append(v);
+ }
+}
+
+// ------------------------------ ArgumentsNode --------------------------------
+
+void ArgumentsNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_listNode)
+ nodeStack.append(m_listNode.get());
+}
+
+// ------------------------------ NewExprNode ----------------------------------
+
+void NewExprNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_args)
+ nodeStack.append(m_args.get());
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 11.2.2
+
+JSValue* NewExprNode::inlineEvaluate(ExecState* exec)
+{
+ JSValue* v = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ List argList;
+ if (m_args) {
+ m_args->evaluateList(exec, argList);
+ KJS_CHECKEXCEPTIONVALUE
+ }
+
+ if (!v->isObject())
+ return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with new.", v, m_expr.get());
+
+ JSObject* constr = static_cast<JSObject*>(v);
+ if (!constr->implementsConstruct())
+ return throwError(exec, TypeError, "Value %s (result of expression %s) is not a constructor. Cannot be used with new.", v, m_expr.get());
+
+ return constr->construct(exec, argList);
+}
+
+JSValue* NewExprNode::evaluate(ExecState* exec)
+{
+ return inlineEvaluate(exec);
+}
+
+double NewExprNode::evaluateToNumber(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toNumber(exec);
+}
+
+bool NewExprNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return v->toBoolean(exec);
+}
+
+int32_t NewExprNode::evaluateToInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toInt32(exec);
+}
+
+uint32_t NewExprNode::evaluateToUInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toUInt32(exec);
+}
+
+void FunctionCallValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_args.get());
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 11.2.3
+JSValue* FunctionCallValueNode::evaluate(ExecState* exec)
+{
+ JSValue* v = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ if (!v->isObject()) {
+ return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_expr.get());
+ }
+
+ JSObject* func = static_cast<JSObject*>(v);
+
+ if (!func->implementsCall()) {
+ return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, m_expr.get());
+ }
+
+ List argList;
+ m_args->evaluateList(exec, argList);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* thisObj = exec->dynamicGlobalObject();
+
+ return func->call(exec, thisObj, argList);
+}
+
+void FunctionCallResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_args.get());
+
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker())
+ new (this) LocalVarFunctionCallNode(index);
+}
+
+// ECMA 11.2.3
+JSValue* FunctionCallResolveNode::inlineEvaluate(ExecState* exec)
+{
+ // Check for missed optimization opportunity.
+ ASSERT(!canSkipLookup(exec, m_ident));
+
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // we must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ JSObject* base;
+ do {
+ base = *iter;
+ if (base->getPropertySlot(exec, m_ident, slot)) {
+ JSValue* v = slot.getValue(exec, base, m_ident);
+ KJS_CHECKEXCEPTIONVALUE
+
+ if (!v->isObject())
+ return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_ident);
+
+ JSObject* func = static_cast<JSObject*>(v);
+
+ if (!func->implementsCall())
+ return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, m_ident);
+
+ List argList;
+ m_args->evaluateList(exec, argList);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* thisObj = base;
+ // ECMA 11.2.3 says that in this situation the this value should be null.
+ // However, section 10.2.3 says that in the case where the value provided
+ // by the caller is null, the global object should be used. It also says
+ // that the section does not apply to internal functions, but for simplicity
+ // of implementation we use the global object anyway here. This guarantees
+ // that in host objects you always get a valid object for this.
+ if (thisObj->isActivationObject())
+ thisObj = exec->dynamicGlobalObject();
+
+ return func->call(exec, thisObj, argList);
+ }
+ ++iter;
+ } while (iter != end);
+
+ return throwUndefinedVariableError(exec, m_ident);
+}
+
+JSValue* FunctionCallResolveNode::evaluate(ExecState* exec)
+{
+ return inlineEvaluate(exec);
+}
+
+double FunctionCallResolveNode::evaluateToNumber(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toNumber(exec);
+}
+
+bool FunctionCallResolveNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return v->toBoolean(exec);
+}
+
+int32_t FunctionCallResolveNode::evaluateToInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toInt32(exec);
+}
+
+uint32_t FunctionCallResolveNode::evaluateToUInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toUInt32(exec);
+}
+
+JSValue* LocalVarFunctionCallNode::inlineEvaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+
+ JSValue* v = exec->localStorage()[m_index].value;
+
+ if (!v->isObject())
+ return throwError(exec, TypeError, "Value %s (result of expression %s) is not object.", v, m_ident);
+
+ JSObject* func = static_cast<JSObject*>(v);
+ if (!func->implementsCall())
+ return throwError(exec, TypeError, "Object %s (result of expression %s) does not allow calls.", v, m_ident);
+
+ List argList;
+ m_args->evaluateList(exec, argList);
+ KJS_CHECKEXCEPTIONVALUE
+
+ return func->call(exec, exec->dynamicGlobalObject(), argList);
+}
+
+JSValue* LocalVarFunctionCallNode::evaluate(ExecState* exec)
+{
+ return inlineEvaluate(exec);
+}
+
+double LocalVarFunctionCallNode::evaluateToNumber(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toNumber(exec);
+}
+
+bool LocalVarFunctionCallNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return v->toBoolean(exec);
+}
+
+int32_t LocalVarFunctionCallNode::evaluateToInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toInt32(exec);
+}
+
+uint32_t LocalVarFunctionCallNode::evaluateToUInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toUInt32(exec);
+}
+
+void FunctionCallBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_args.get());
+ nodeStack.append(m_subscript.get());
+ nodeStack.append(m_base.get());
+}
+
+// ECMA 11.2.3
+JSValue* FunctionCallBracketNode::evaluate(ExecState* exec)
+{
+ JSValue* baseVal = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* subscriptVal = m_subscript->evaluate(exec);
+
+ JSObject* baseObj = baseVal->toObject(exec);
+ uint32_t i;
+ PropertySlot slot;
+
+ JSValue* funcVal;
+ if (subscriptVal->getUInt32(i)) {
+ if (baseObj->getPropertySlot(exec, i, slot))
+ funcVal = slot.getValue(exec, baseObj, i);
+ else
+ funcVal = jsUndefined();
+ } else {
+ Identifier ident(subscriptVal->toString(exec));
+ if (baseObj->getPropertySlot(exec, ident, slot))
+ funcVal = baseObj->get(exec, ident);
+ else
+ funcVal = jsUndefined();
+ }
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ if (!funcVal->isObject())
+ return throwError(exec, TypeError, "Value %s (result of expression %s[%s]) is not object.", funcVal, m_base.get(), m_subscript.get());
+
+ JSObject* func = static_cast<JSObject*>(funcVal);
+
+ if (!func->implementsCall())
+ return throwError(exec, TypeError, "Object %s (result of expression %s[%s]) does not allow calls.", funcVal, m_base.get(), m_subscript.get());
+
+ List argList;
+ m_args->evaluateList(exec, argList);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* thisObj = baseObj;
+ ASSERT(thisObj);
+ ASSERT(thisObj->isObject());
+ ASSERT(!thisObj->isActivationObject());
+
+ return func->call(exec, thisObj, argList);
+}
+
+static const char* dotExprNotAnObjectString() KJS_FAST_CALL;
+static const char* dotExprNotAnObjectString()
+{
+ return "Value %s (result of expression %s.%s) is not object.";
+}
+
+static const char* dotExprDoesNotAllowCallsString() KJS_FAST_CALL;
+static const char* dotExprDoesNotAllowCallsString()
+{
+ return "Object %s (result of expression %s.%s) does not allow calls.";
+}
+
+void FunctionCallDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_args.get());
+ nodeStack.append(m_base.get());
+}
+
+// ECMA 11.2.3
+JSValue* FunctionCallDotNode::inlineEvaluate(ExecState* exec)
+{
+ JSValue* baseVal = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* baseObj = baseVal->toObject(exec);
+ PropertySlot slot;
+ JSValue* funcVal = baseObj->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, baseObj, m_ident) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ if (!funcVal->isObject())
+ return throwError(exec, TypeError, dotExprNotAnObjectString(), funcVal, m_base.get(), m_ident);
+
+ JSObject* func = static_cast<JSObject*>(funcVal);
+
+ if (!func->implementsCall())
+ return throwError(exec, TypeError, dotExprDoesNotAllowCallsString(), funcVal, m_base.get(), m_ident);
+
+ List argList;
+ m_args->evaluateList(exec, argList);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* thisObj = baseObj;
+ ASSERT(thisObj);
+ ASSERT(thisObj->isObject());
+ ASSERT(!thisObj->isActivationObject());
+
+ return func->call(exec, thisObj, argList);
+}
+
+JSValue* FunctionCallDotNode::evaluate(ExecState* exec)
+{
+ return inlineEvaluate(exec);
+}
+
+double FunctionCallDotNode::evaluateToNumber(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toNumber(exec);
+}
+
+bool FunctionCallDotNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return v->toBoolean(exec);
+}
+
+int32_t FunctionCallDotNode::evaluateToInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toInt32(exec);
+}
+
+uint32_t FunctionCallDotNode::evaluateToUInt32(ExecState* exec)
+{
+ JSValue* v = inlineEvaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return v->toUInt32(exec);
+}
+
+// ECMA 11.3
+
+// ------------------------------ PostfixResolveNode ----------------------------------
+
+// Increment
+void PostIncResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
+{
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker()) {
+ if (isConstant(localStorage, index))
+ new (this) PostIncConstNode(index);
+ else
+ new (this) PostIncLocalVarNode(index);
+ }
+}
+
+JSValue* PostIncResolveNode::evaluate(ExecState* exec)
+{
+ // Check for missed optimization opportunity.
+ ASSERT(!canSkipLookup(exec, m_ident));
+
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // we must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ do {
+ if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
+ // If m_ident is 'arguments', the base->getPropertySlot() may cause
+ // base (which must be an ActivationImp in such this case) to be torn
+ // off from the activation stack, in which case we need to get it again
+ // from the ScopeChainIterator.
+
+ JSObject* base = *iter;
+ JSValue* v = slot.getValue(exec, base, m_ident)->toJSNumber(exec);
+ base->put(exec, m_ident, jsNumber(v->toNumber(exec) + 1));
+ return v;
+ }
+
+ ++iter;
+ } while (iter != end);
+
+ return throwUndefinedVariableError(exec, m_ident);
+}
+
+void PostIncResolveNode::optimizeForUnnecessaryResult()
+{
+ new (this) PreIncResolveNode(PlacementNewAdopt);
+}
+
+JSValue* PostIncLocalVarNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+
+ JSValue** slot = &exec->localStorage()[m_index].value;
+ JSValue* v = (*slot)->toJSNumber(exec);
+ *slot = jsNumber(v->toNumber(exec) + 1);
+ return v;
+}
+
+void PostIncLocalVarNode::optimizeForUnnecessaryResult()
+{
+ new (this) PreIncLocalVarNode(m_index);
+}
+
+// Decrement
+void PostDecResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
+{
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker()) {
+ if (isConstant(localStorage, index))
+ new (this) PostDecConstNode(index);
+ else
+ new (this) PostDecLocalVarNode(index);
+ }
+}
+
+JSValue* PostDecResolveNode::evaluate(ExecState* exec)
+{
+ // Check for missed optimization opportunity.
+ ASSERT(!canSkipLookup(exec, m_ident));
+
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // we must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ do {
+ if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
+ // See the comment in PostIncResolveNode::evaluate().
+
+ JSObject* base = *iter;
+ JSValue* v = slot.getValue(exec, base, m_ident)->toJSNumber(exec);
+ base->put(exec, m_ident, jsNumber(v->toNumber(exec) - 1));
+ return v;
+ }
+
+ ++iter;
+ } while (iter != end);
+
+ return throwUndefinedVariableError(exec, m_ident);
+}
+
+void PostDecResolveNode::optimizeForUnnecessaryResult()
+{
+ new (this) PreDecResolveNode(PlacementNewAdopt);
+}
+
+JSValue* PostDecLocalVarNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+
+ JSValue** slot = &exec->localStorage()[m_index].value;
+ JSValue* v = (*slot)->toJSNumber(exec);
+ *slot = jsNumber(v->toNumber(exec) - 1);
+ return v;
+}
+
+double PostDecLocalVarNode::inlineEvaluateToNumber(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+
+ JSValue** slot = &exec->localStorage()[m_index].value;
+ double n = (*slot)->toNumber(exec);
+ *slot = jsNumber(n - 1);
+ return n;
+}
+
+double PostDecLocalVarNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToNumber(exec);
+}
+
+bool PostDecLocalVarNode::evaluateToBoolean(ExecState* exec)
+{
+ double result = inlineEvaluateToNumber(exec);
+ return result > 0.0 || 0.0 > result; // NaN produces false as well
+}
+
+int32_t PostDecLocalVarNode::evaluateToInt32(ExecState* exec)
+{
+ return JSValue::toInt32(inlineEvaluateToNumber(exec));
+}
+
+uint32_t PostDecLocalVarNode::evaluateToUInt32(ExecState* exec)
+{
+ return JSValue::toUInt32(inlineEvaluateToNumber(exec));
+}
+
+void PostDecLocalVarNode::optimizeForUnnecessaryResult()
+{
+ new (this) PreDecLocalVarNode(m_index);
+}
+
+// ------------------------------ PostfixBracketNode ----------------------------------
+
+void PostfixBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_subscript.get());
+ nodeStack.append(m_base.get());
+}
+
+JSValue* PostIncBracketNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* subscript = m_subscript->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* base = baseValue->toObject(exec);
+
+ uint32_t propertyIndex;
+ if (subscript->getUInt32(propertyIndex)) {
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = v->toJSNumber(exec);
+ base->put(exec, propertyIndex, jsNumber(v2->toNumber(exec) + 1));
+
+ return v2;
+ }
+
+ Identifier propertyName(subscript->toString(exec));
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = v->toJSNumber(exec);
+ base->put(exec, propertyName, jsNumber(v2->toNumber(exec) + 1));
+ return v2;
+}
+
+JSValue* PostDecBracketNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* subscript = m_subscript->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* base = baseValue->toObject(exec);
+
+ uint32_t propertyIndex;
+ if (subscript->getUInt32(propertyIndex)) {
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = v->toJSNumber(exec);
+ base->put(exec, propertyIndex, jsNumber(v2->toNumber(exec) - 1));
+ return v2;
+ }
+
+ Identifier propertyName(subscript->toString(exec));
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = v->toJSNumber(exec);
+ base->put(exec, propertyName, jsNumber(v2->toNumber(exec) - 1));
+ return v2;
+}
+
+// ------------------------------ PostfixDotNode ----------------------------------
+
+void PostfixDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_base.get());
+}
+
+JSValue* PostIncDotNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSObject* base = baseValue->toObject(exec);
+
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = v->toJSNumber(exec);
+ base->put(exec, m_ident, jsNumber(v2->toNumber(exec) + 1));
+ return v2;
+}
+
+JSValue* PostDecDotNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSObject* base = baseValue->toObject(exec);
+
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = v->toJSNumber(exec);
+ base->put(exec, m_ident, jsNumber(v2->toNumber(exec) - 1));
+ return v2;
+}
+
+// ------------------------------ PostfixErrorNode -----------------------------------
+
+JSValue* PostfixErrorNode::evaluate(ExecState* exec)
+{
+ throwError(exec, ReferenceError, "Postfix %s operator applied to value that is not a reference.",
+ m_operator == OpPlusPlus ? "++" : "--");
+ handleException(exec);
+ return jsUndefined();
+}
+
+// ------------------------------ DeleteResolveNode -----------------------------------
+
+void DeleteResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
+{
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker())
+ new (this) LocalVarDeleteNode();
+}
+
+// ECMA 11.4.1
+
+JSValue* DeleteResolveNode::evaluate(ExecState* exec)
+{
+ // Check for missed optimization opportunity.
+ ASSERT(!canSkipLookup(exec, m_ident));
+
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // We must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ JSObject* base;
+ do {
+ base = *iter;
+ if (base->getPropertySlot(exec, m_ident, slot))
+ return jsBoolean(base->deleteProperty(exec, m_ident));
+
+ ++iter;
+ } while (iter != end);
+
+ return jsBoolean(true);
+}
+
+JSValue* LocalVarDeleteNode::evaluate(ExecState*)
+{
+ return jsBoolean(false);
+}
+
+// ------------------------------ DeleteBracketNode -----------------------------------
+
+void DeleteBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_subscript.get());
+ nodeStack.append(m_base.get());
+}
+
+JSValue* DeleteBracketNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* subscript = m_subscript->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* base = baseValue->toObject(exec);
+
+ uint32_t propertyIndex;
+ if (subscript->getUInt32(propertyIndex))
+ return jsBoolean(base->deleteProperty(exec, propertyIndex));
+
+ Identifier propertyName(subscript->toString(exec));
+ return jsBoolean(base->deleteProperty(exec, propertyName));
+}
+
+// ------------------------------ DeleteDotNode -----------------------------------
+
+void DeleteDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_base.get());
+}
+
+JSValue* DeleteDotNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ JSObject* base = baseValue->toObject(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ return jsBoolean(base->deleteProperty(exec, m_ident));
+}
+
+// ------------------------------ DeleteValueNode -----------------------------------
+
+void DeleteValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr.get());
+}
+
+JSValue* DeleteValueNode::evaluate(ExecState* exec)
+{
+ m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ // delete on a non-location expression ignores the value and returns true
+ return jsBoolean(true);
+}
+
+// ------------------------------ VoidNode -------------------------------------
+
+void VoidNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 11.4.2
+JSValue* VoidNode::evaluate(ExecState* exec)
+{
+ m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ return jsUndefined();
+}
+
+// ECMA 11.4.3
+
+// ------------------------------ TypeOfValueNode -----------------------------------
+
+void TypeOfValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr.get());
+}
+
+static JSValue* typeStringForValue(JSValue* v) KJS_FAST_CALL;
+static JSValue* typeStringForValue(JSValue* v)
+{
+ switch (v->type()) {
+ case UndefinedType:
+ return jsString("undefined");
+ case NullType:
+ return jsString("object");
+ case BooleanType:
+ return jsString("boolean");
+ case NumberType:
+ return jsString("number");
+ case StringType:
+ return jsString("string");
+ default:
+ if (v->isObject()) {
+ // Return "undefined" for objects that should be treated
+ // as null when doing comparisons.
+ if (static_cast<JSObject*>(v)->masqueradeAsUndefined())
+ return jsString("undefined");
+ else if (static_cast<JSObject*>(v)->implementsCall())
+ return jsString("function");
+ }
+
+ return jsString("object");
+ }
+}
+
+void TypeOfResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage&, NodeStack&)
+{
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker())
+ new (this) LocalVarTypeOfNode(index);
+}
+
+JSValue* LocalVarTypeOfNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+
+ return typeStringForValue(exec->localStorage()[m_index].value);
+}
+
+JSValue* TypeOfResolveNode::evaluate(ExecState* exec)
+{
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // We must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ JSObject* base;
+ do {
+ base = *iter;
+ if (base->getPropertySlot(exec, m_ident, slot)) {
+ JSValue* v = slot.getValue(exec, base, m_ident);
+ return typeStringForValue(v);
+ }
+
+ ++iter;
+ } while (iter != end);
+
+ return jsString("undefined");
+}
+
+// ------------------------------ TypeOfValueNode -----------------------------------
+
+JSValue* TypeOfValueNode::evaluate(ExecState* exec)
+{
+ JSValue* v = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ return typeStringForValue(v);
+}
+
+// ECMA 11.4.4 and 11.4.5
+
+// ------------------------------ PrefixResolveNode ----------------------------------
+
+void PreIncResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
+{
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker()) {
+ if (isConstant(localStorage, index))
+ new (this) PreIncConstNode(index);
+ else
+ new (this) PreIncLocalVarNode(index);
+ }
+}
+
+JSValue* PreIncLocalVarNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+ JSValue** slot = &exec->localStorage()[m_index].value;
+
+ double n = (*slot)->toNumber(exec);
+ JSValue* n2 = jsNumber(n + 1);
+ *slot = n2;
+ return n2;
+}
+
+JSValue* PreIncResolveNode::evaluate(ExecState* exec)
+{
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // we must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ do {
+ if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
+ // See the comment in PostIncResolveNode::evaluate().
+
+ JSObject* base = *iter;
+ JSValue* v = slot.getValue(exec, base, m_ident);
+
+ double n = v->toNumber(exec);
+ JSValue* n2 = jsNumber(n + 1);
+ base->put(exec, m_ident, n2);
+
+ return n2;
+ }
+
+ ++iter;
+ } while (iter != end);
+
+ return throwUndefinedVariableError(exec, m_ident);
+}
+
+void PreDecResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack&)
+{
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker()) {
+ if (isConstant(localStorage, index))
+ new (this) PreDecConstNode(index);
+ else
+ new (this) PreDecLocalVarNode(index);
+ }
+}
+
+JSValue* PreDecLocalVarNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+ JSValue** slot = &exec->localStorage()[m_index].value;
+
+ double n = (*slot)->toNumber(exec);
+ JSValue* n2 = jsNumber(n - 1);
+ *slot = n2;
+ return n2;
+}
+
+JSValue* PreDecResolveNode::evaluate(ExecState* exec)
+{
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // we must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ do {
+ if ((*iter)->getPropertySlot(exec, m_ident, slot)) {
+ // See the comment in PostIncResolveNode::evaluate().
+
+ JSObject* base = *iter;
+ JSValue* v = slot.getValue(exec, base, m_ident);
+
+ double n = v->toNumber(exec);
+ JSValue* n2 = jsNumber(n - 1);
+ base->put(exec, m_ident, n2);
+
+ return n2;
+ }
+
+ ++iter;
+ } while (iter != end);
+
+ return throwUndefinedVariableError(exec, m_ident);
+}
+
+// ------------------------------ PreIncConstNode ----------------------------------
+
+JSValue* PreIncConstNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+ return jsNumber(exec->localStorage()[m_index].value->toNumber(exec) + 1);
+}
+
+// ------------------------------ PreDecConstNode ----------------------------------
+
+JSValue* PreDecConstNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+ return jsNumber(exec->localStorage()[m_index].value->toNumber(exec) - 1);
+}
+
+// ------------------------------ PostIncConstNode ----------------------------------
+
+JSValue* PostIncConstNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+ return jsNumber(exec->localStorage()[m_index].value->toNumber(exec));
+}
+
+// ------------------------------ PostDecConstNode ----------------------------------
+
+JSValue* PostDecConstNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+ return jsNumber(exec->localStorage()[m_index].value->toNumber(exec));
+}
+
+// ------------------------------ PrefixBracketNode ----------------------------------
+
+void PrefixBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_subscript.get());
+ nodeStack.append(m_base.get());
+}
+
+JSValue* PreIncBracketNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* subscript = m_subscript->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* base = baseValue->toObject(exec);
+
+ uint32_t propertyIndex;
+ if (subscript->getUInt32(propertyIndex)) {
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* n2 = jsNumber(v->toNumber(exec) + 1);
+ base->put(exec, propertyIndex, n2);
+
+ return n2;
+ }
+
+ Identifier propertyName(subscript->toString(exec));
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* n2 = jsNumber(v->toNumber(exec) + 1);
+ base->put(exec, propertyName, n2);
+
+ return n2;
+}
+
+JSValue* PreDecBracketNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* subscript = m_subscript->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* base = baseValue->toObject(exec);
+
+ uint32_t propertyIndex;
+ if (subscript->getUInt32(propertyIndex)) {
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* n2 = jsNumber(v->toNumber(exec) - 1);
+ base->put(exec, propertyIndex, n2);
+
+ return n2;
+ }
+
+ Identifier propertyName(subscript->toString(exec));
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* n2 = jsNumber(v->toNumber(exec) - 1);
+ base->put(exec, propertyName, n2);
+
+ return n2;
+}
+
+// ------------------------------ PrefixDotNode ----------------------------------
+
+void PrefixDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_base.get());
+}
+
+JSValue* PreIncDotNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSObject* base = baseValue->toObject(exec);
+
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ double n = v->toNumber(exec);
+ JSValue* n2 = jsNumber(n + 1);
+ base->put(exec, m_ident, n2);
+
+ return n2;
+}
+
+JSValue* PreDecDotNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSObject* base = baseValue->toObject(exec);
+
+ PropertySlot slot;
+ JSValue* v = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+
+ double n = v->toNumber(exec);
+ JSValue* n2 = jsNumber(n - 1);
+ base->put(exec, m_ident, n2);
+
+ return n2;
+}
+
+// ------------------------------ PrefixErrorNode -----------------------------------
+
+JSValue* PrefixErrorNode::evaluate(ExecState* exec)
+{
+ throwError(exec, ReferenceError, "Prefix %s operator applied to value that is not a reference.",
+ m_operator == OpPlusPlus ? "++" : "--");
+ handleException(exec);
+ return jsUndefined();
+}
+
+// ------------------------------ UnaryPlusNode --------------------------------
+
+void UnaryPlusNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 11.4.6
+JSValue* UnaryPlusNode::evaluate(ExecState* exec)
+{
+ JSValue* v = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ return v->toJSNumber(exec);
+}
+
+bool UnaryPlusNode::evaluateToBoolean(ExecState* exec)
+{
+ return m_expr->evaluateToBoolean(exec);
+}
+
+double UnaryPlusNode::evaluateToNumber(ExecState* exec)
+{
+ return m_expr->evaluateToNumber(exec);
+}
+
+int32_t UnaryPlusNode::evaluateToInt32(ExecState* exec)
+{
+ return m_expr->evaluateToInt32(exec);
+}
+
+uint32_t UnaryPlusNode::evaluateToUInt32(ExecState* exec)
+{
+ return m_expr->evaluateToInt32(exec);
+}
+
+// ------------------------------ NegateNode -----------------------------------
+
+void NegateNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 11.4.7
+JSValue* NegateNode::evaluate(ExecState* exec)
+{
+ // No need to check exception, caller will do so right after evaluate()
+ return jsNumber(-m_expr->evaluateToNumber(exec));
+}
+
+double NegateNode::evaluateToNumber(ExecState* exec)
+{
+ // No need to check exception, caller will do so right after evaluateToNumber()
+ return -m_expr->evaluateToNumber(exec);
+}
+
+// ------------------------------ BitwiseNotNode -------------------------------
+
+void BitwiseNotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 11.4.8
+int32_t BitwiseNotNode::inlineEvaluateToInt32(ExecState* exec)
+{
+ return ~m_expr->evaluateToInt32(exec);
+}
+
+JSValue* BitwiseNotNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToInt32(exec));
+}
+
+double BitwiseNotNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+bool BitwiseNotNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+int32_t BitwiseNotNode::evaluateToInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+uint32_t BitwiseNotNode::evaluateToUInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+// ------------------------------ LogicalNotNode -------------------------------
+
+void LogicalNotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 11.4.9
+JSValue* LogicalNotNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(!m_expr->evaluateToBoolean(exec));
+}
+
+bool LogicalNotNode::evaluateToBoolean(ExecState* exec)
+{
+ return !m_expr->evaluateToBoolean(exec);
+}
+
+// ------------------------------ Multiplicative Nodes -----------------------------------
+
+void MultNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_term1.get());
+ nodeStack.append(m_term2.get());
+}
+
+// ECMA 11.5.1
+double MultNode::inlineEvaluateToNumber(ExecState* exec)
+{
+ double n1 = m_term1->evaluateToNumber(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ double n2 = m_term2->evaluateToNumber(exec);
+ return n1 * n2;
+}
+
+JSValue* MultNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToNumber(exec));
+}
+
+double MultNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToNumber(exec);
+}
+
+bool MultNode::evaluateToBoolean(ExecState* exec)
+{
+ double result = inlineEvaluateToNumber(exec);
+ return result > 0.0 || 0.0 > result; // NaN produces false as well
+}
+
+int32_t MultNode::evaluateToInt32(ExecState* exec)
+{
+ return JSValue::toInt32(inlineEvaluateToNumber(exec));
+}
+
+uint32_t MultNode::evaluateToUInt32(ExecState* exec)
+{
+ return JSValue::toUInt32(inlineEvaluateToNumber(exec));
+}
+
+void DivNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_term1.get());
+ nodeStack.append(m_term2.get());
+}
+
+// ECMA 11.5.2
+double DivNode::inlineEvaluateToNumber(ExecState* exec)
+{
+ double n1 = m_term1->evaluateToNumber(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ double n2 = m_term2->evaluateToNumber(exec);
+ return n1 / n2;
+}
+
+JSValue* DivNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToNumber(exec));
+}
+
+double DivNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToNumber(exec);
+}
+
+int32_t DivNode::evaluateToInt32(ExecState* exec)
+{
+ return JSValue::toInt32(inlineEvaluateToNumber(exec));
+}
+
+uint32_t DivNode::evaluateToUInt32(ExecState* exec)
+{
+ return JSValue::toUInt32(inlineEvaluateToNumber(exec));
+}
+
+void ModNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_term1.get());
+ nodeStack.append(m_term2.get());
+}
+
+// ECMA 11.5.3
+double ModNode::inlineEvaluateToNumber(ExecState* exec)
+{
+ double n1 = m_term1->evaluateToNumber(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ double n2 = m_term2->evaluateToNumber(exec);
+ return fmod(n1, n2);
+}
+
+JSValue* ModNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToNumber(exec));
+}
+
+double ModNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToNumber(exec);
+}
+
+bool ModNode::evaluateToBoolean(ExecState* exec)
+{
+ double result = inlineEvaluateToNumber(exec);
+ return result > 0.0 || 0.0 > result; // NaN produces false as well
+}
+
+int32_t ModNode::evaluateToInt32(ExecState* exec)
+{
+ return JSValue::toInt32(inlineEvaluateToNumber(exec));
+}
+
+uint32_t ModNode::evaluateToUInt32(ExecState* exec)
+{
+ return JSValue::toUInt32(inlineEvaluateToNumber(exec));
+}
+
+// ------------------------------ Additive Nodes --------------------------------------
+
+static JSValue* throwOutOfMemoryError(ExecState* exec)
+{
+ JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+ exec->setException(error);
+ return error;
+}
+
+static double throwOutOfMemoryErrorToNumber(ExecState* exec)
+{
+ JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+ exec->setException(error);
+ return 0.0;
+}
+
+// ECMA 11.6
+static JSValue* addSlowCase(ExecState* exec, JSValue* v1, JSValue* v2)
+{
+ // exception for the Date exception in defaultValue()
+ JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
+ JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
+
+ if (p1->isString() || p2->isString()) {
+ UString value = p1->toString(exec) + p2->toString(exec);
+ if (value.isNull())
+ return throwOutOfMemoryError(exec);
+ return jsString(value);
+ }
+
+ return jsNumber(p1->toNumber(exec) + p2->toNumber(exec));
+}
+
+static double addSlowCaseToNumber(ExecState* exec, JSValue* v1, JSValue* v2)
+{
+ // exception for the Date exception in defaultValue()
+ JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
+ JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
+
+ if (p1->isString() || p2->isString()) {
+ UString value = p1->toString(exec) + p2->toString(exec);
+ if (value.isNull())
+ return throwOutOfMemoryErrorToNumber(exec);
+ return value.toDouble();
+ }
+
+ return p1->toNumber(exec) + p2->toNumber(exec);
+}
+
+// Fast-path choices here are based on frequency data from SunSpider:
+// <times> Add case: <t1> <t2>
+// ---------------------------
+// 5627160 Add case: 1 1
+// 247427 Add case: 5 5
+// 20901 Add case: 5 6
+// 13978 Add case: 5 1
+// 4000 Add case: 1 5
+// 1 Add case: 3 5
+
+static inline JSValue* add(ExecState* exec, JSValue* v1, JSValue* v2)
+{
+ JSType t1 = v1->type();
+ JSType t2 = v2->type();
+ const unsigned bothTypes = (t1 << 3) | t2;
+
+ if (bothTypes == ((NumberType << 3) | NumberType))
+ return jsNumber(v1->toNumber(exec) + v2->toNumber(exec));
+ if (bothTypes == ((StringType << 3) | StringType)) {
+ UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
+ if (value.isNull())
+ return throwOutOfMemoryError(exec);
+ return jsString(value);
+ }
+
+ // All other cases are pretty uncommon
+ return addSlowCase(exec, v1, v2);
+}
+
+static inline double addToNumber(ExecState* exec, JSValue* v1, JSValue* v2)
+{
+ JSType t1 = v1->type();
+ JSType t2 = v2->type();
+ const unsigned bothTypes = (t1 << 3) | t2;
+
+ if (bothTypes == ((NumberType << 3) | NumberType))
+ return v1->toNumber(exec) + v2->toNumber(exec);
+ if (bothTypes == ((StringType << 3) | StringType)) {
+ UString value = static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value();
+ if (value.isNull())
+ return throwOutOfMemoryErrorToNumber(exec);
+ return value.toDouble();
+ }
+
+ // All other cases are pretty uncommon
+ return addSlowCaseToNumber(exec, v1, v2);
+}
+
+void AddNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_term1.get());
+ nodeStack.append(m_term2.get());
+}
+
+// ECMA 11.6.1
+JSValue* AddNode::evaluate(ExecState* exec)
+{
+ JSValue* v1 = m_term1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = m_term2->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ return add(exec, v1, v2);
+}
+
+double AddNode::inlineEvaluateToNumber(ExecState* exec)
+{
+ JSValue* v1 = m_term1->evaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+
+ JSValue* v2 = m_term2->evaluate(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+
+ return addToNumber(exec, v1, v2);
+}
+
+double AddNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToNumber(exec);
+}
+
+int32_t AddNode::evaluateToInt32(ExecState* exec)
+{
+ return JSValue::toInt32(inlineEvaluateToNumber(exec));
+}
+
+uint32_t AddNode::evaluateToUInt32(ExecState* exec)
+{
+ return JSValue::toUInt32(inlineEvaluateToNumber(exec));
+}
+
+double AddNumbersNode::inlineEvaluateToNumber(ExecState* exec)
+{
+ double n1 = m_term1->evaluateToNumber(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ double n2 = m_term2->evaluateToNumber(exec);
+ return n1 + n2;
+}
+
+JSValue* AddNumbersNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToNumber(exec));
+}
+
+double AddNumbersNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToNumber(exec);
+}
+
+int32_t AddNumbersNode::evaluateToInt32(ExecState* exec)
+{
+ return JSValue::toInt32(inlineEvaluateToNumber(exec));
+}
+
+uint32_t AddNumbersNode::evaluateToUInt32(ExecState* exec)
+{
+ return JSValue::toUInt32(inlineEvaluateToNumber(exec));
+}
+
+JSValue* AddStringsNode::evaluate(ExecState* exec)
+{
+ JSValue* v1 = m_term1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = m_term2->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ return jsString(static_cast<StringImp*>(v1)->value() + static_cast<StringImp*>(v2)->value());
+}
+
+JSValue* AddStringLeftNode::evaluate(ExecState* exec)
+{
+ JSValue* v1 = m_term1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = m_term2->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* p2 = v2->toPrimitive(exec, UnspecifiedType);
+ return jsString(static_cast<StringImp*>(v1)->value() + p2->toString(exec));
+}
+
+JSValue* AddStringRightNode::evaluate(ExecState* exec)
+{
+ JSValue* v1 = m_term1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* v2 = m_term2->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSValue* p1 = v1->toPrimitive(exec, UnspecifiedType);
+ return jsString(p1->toString(exec) + static_cast<StringImp*>(v2)->value());
+}
+
+void SubNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_term1.get());
+ nodeStack.append(m_term2.get());
+}
+
+// ECMA 11.6.2
+double SubNode::inlineEvaluateToNumber(ExecState* exec)
+{
+ double n1 = m_term1->evaluateToNumber(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ double n2 = m_term2->evaluateToNumber(exec);
+ return n1 - n2;
+}
+
+JSValue* SubNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToNumber(exec));
+}
+
+double SubNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToNumber(exec);
+}
+
+int32_t SubNode::evaluateToInt32(ExecState* exec)
+{
+ return JSValue::toInt32(inlineEvaluateToNumber(exec));
+}
+
+uint32_t SubNode::evaluateToUInt32(ExecState* exec)
+{
+ return JSValue::toUInt32(inlineEvaluateToNumber(exec));
+}
+
+// ------------------------------ Shift Nodes ------------------------------------
+
+void LeftShiftNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_term1.get());
+ nodeStack.append(m_term2.get());
+}
+
+// ECMA 11.7.1
+int32_t LeftShiftNode::inlineEvaluateToInt32(ExecState* exec)
+{
+ int i1 = m_term1->evaluateToInt32(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ unsigned int i2 = m_term2->evaluateToUInt32(exec) & 0x1f;
+ return (i1 << i2);
+}
+
+JSValue* LeftShiftNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToInt32(exec));
+}
+
+double LeftShiftNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+int32_t LeftShiftNode::evaluateToInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+uint32_t LeftShiftNode::evaluateToUInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+void RightShiftNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_term1.get());
+ nodeStack.append(m_term2.get());
+}
+
+// ECMA 11.7.2
+int32_t RightShiftNode::inlineEvaluateToInt32(ExecState* exec)
+{
+ int i1 = m_term1->evaluateToInt32(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ unsigned int i2 = m_term2->evaluateToUInt32(exec) & 0x1f;
+ return (i1 >> i2);
+}
+
+JSValue* RightShiftNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToInt32(exec));
+}
+
+double RightShiftNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+int32_t RightShiftNode::evaluateToInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+uint32_t RightShiftNode::evaluateToUInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+void UnsignedRightShiftNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_term1.get());
+ nodeStack.append(m_term2.get());
+}
+
+// ECMA 11.7.3
+uint32_t UnsignedRightShiftNode::inlineEvaluateToUInt32(ExecState* exec)
+{
+ unsigned int i1 = m_term1->evaluateToUInt32(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ unsigned int i2 = m_term2->evaluateToUInt32(exec) & 0x1f;
+ return (i1 >> i2);
+}
+
+JSValue* UnsignedRightShiftNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToUInt32(exec));
+}
+
+double UnsignedRightShiftNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToUInt32(exec);
+}
+
+int32_t UnsignedRightShiftNode::evaluateToInt32(ExecState* exec)
+{
+ return inlineEvaluateToUInt32(exec);
+}
+
+uint32_t UnsignedRightShiftNode::evaluateToUInt32(ExecState* exec)
+{
+ return inlineEvaluateToUInt32(exec);
+}
+
+// ------------------------------ Relational Nodes -------------------------------
+
+static inline bool lessThan(ExecState* exec, JSValue* v1, JSValue* v2)
+{
+ double n1;
+ double n2;
+ JSValue* p1;
+ JSValue* p2;
+ bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
+ bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
+
+ if (wasNotString1 | wasNotString2)
+ return n1 < n2;
+
+ return static_cast<const StringImp*>(p1)->value() < static_cast<const StringImp*>(p2)->value();
+}
+
+static inline bool lessThanEq(ExecState* exec, JSValue* v1, JSValue* v2)
+{
+ double n1;
+ double n2;
+ JSValue* p1;
+ JSValue* p2;
+ bool wasNotString1 = v1->getPrimitiveNumber(exec, n1, p1);
+ bool wasNotString2 = v2->getPrimitiveNumber(exec, n2, p2);
+
+ if (wasNotString1 | wasNotString2)
+ return n1 <= n2;
+
+ return !(static_cast<const StringImp*>(p2)->value() < static_cast<const StringImp*>(p1)->value());
+}
+
+void LessNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.8.1
+bool LessNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return lessThan(exec, v1, v2);
+}
+
+JSValue* LessNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool LessNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+bool LessNumbersNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ double n1 = m_expr1->evaluateToNumber(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ double n2 = m_expr2->evaluateToNumber(exec);
+ return n1 < n2;
+}
+
+JSValue* LessNumbersNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool LessNumbersNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+bool LessStringsNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* v2 = m_expr2->evaluate(exec);
+ return static_cast<StringImp*>(v1)->value() < static_cast<StringImp*>(v2)->value();
+}
+
+JSValue* LessStringsNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool LessStringsNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+void GreaterNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.8.2
+bool GreaterNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return lessThan(exec, v2, v1);
+}
+
+JSValue* GreaterNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool GreaterNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+void LessEqNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.8.3
+bool LessEqNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return lessThanEq(exec, v1, v2);
+}
+
+JSValue* LessEqNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool LessEqNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+void GreaterEqNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.8.4
+bool GreaterEqNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return lessThanEq(exec, v2, v1);
+}
+
+JSValue* GreaterEqNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool GreaterEqNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+void InstanceOfNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.8.6
+JSValue* InstanceOfNode::evaluate(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ if (!v2->isObject())
+ return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with instanceof operator.", v2, m_expr2.get());
+
+ JSObject* o2 = static_cast<JSObject*>(v2);
+
+ // According to the spec, only some types of objects "implement" the [[HasInstance]] property.
+ // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]]
+ // property. It seems that all objects have the property, but not all implement it, so in this
+ // case we return false (consistent with Mozilla).
+ if (!o2->implementsHasInstance())
+ return jsBoolean(false);
+
+ return jsBoolean(o2->hasInstance(exec, v1));
+}
+
+bool InstanceOfNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+
+ if (!v2->isObject()) {
+ throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with 'instanceof' operator.", v2, m_expr2.get());
+ return false;
+ }
+
+ JSObject* o2 = static_cast<JSObject*>(v2);
+
+ // According to the spec, only some types of objects "implement" the [[HasInstance]] property.
+ // But we are supposed to throw an exception where the object does not "have" the [[HasInstance]]
+ // property. It seems that all objects have the property, but not all implement it, so in this
+ // case we return false (consistent with Mozilla).
+ if (!o2->implementsHasInstance())
+ return false;
+
+ return o2->hasInstance(exec, v1);
+}
+
+void InNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.8.7
+JSValue* InNode::evaluate(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ if (!v2->isObject())
+ return throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with 'in' operator.", v2, m_expr2.get());
+
+ return jsBoolean(static_cast<JSObject*>(v2)->hasProperty(exec, Identifier(v1->toString(exec))));
+}
+
+bool InNode::evaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+
+ if (!v2->isObject()) {
+ throwError(exec, TypeError, "Value %s (result of expression %s) is not an object. Cannot be used with 'in' operator.", v2, m_expr2.get());
+ return false;
+ }
+
+ return static_cast<JSObject*>(v2)->hasProperty(exec, Identifier(v1->toString(exec)));
+}
+
+// ------------------------------ Equality Nodes ------------------------------------
+
+void EqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.9.1
+bool EqualNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+
+ return equal(exec, v1, v2);
+}
+
+JSValue* EqualNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool EqualNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+void NotEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.9.2
+bool NotEqualNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+
+ return !equal(exec,v1, v2);
+}
+
+JSValue* NotEqualNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool NotEqualNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+void StrictEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.9.4
+bool StrictEqualNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+
+ return strictEqual(exec,v1, v2);
+}
+
+JSValue* StrictEqualNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool StrictEqualNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+void NotStrictEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.9.5
+bool NotStrictEqualNode::inlineEvaluateToBoolean(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+
+ return !strictEqual(exec,v1, v2);
+}
+
+JSValue* NotStrictEqualNode::evaluate(ExecState* exec)
+{
+ return jsBoolean(inlineEvaluateToBoolean(exec));
+}
+
+bool NotStrictEqualNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToBoolean(exec);
+}
+
+// ------------------------------ Bit Operation Nodes ----------------------------------
+
+void BitAndNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.10
+JSValue* BitAndNode::evaluate(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ return jsNumberFromAnd(exec, v1, v2);
+}
+
+int32_t BitAndNode::inlineEvaluateToInt32(ExecState* exec)
+{
+ int32_t i1 = m_expr1->evaluateToInt32(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ int32_t i2 = m_expr2->evaluateToInt32(exec);
+ return (i1 & i2);
+}
+
+double BitAndNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+bool BitAndNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+int32_t BitAndNode::evaluateToInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+uint32_t BitAndNode::evaluateToUInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+void BitXOrNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+int32_t BitXOrNode::inlineEvaluateToInt32(ExecState* exec)
+{
+ int i1 = m_expr1->evaluateToInt32(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ int i2 = m_expr2->evaluateToInt32(exec);
+ return (i1 ^ i2);
+}
+
+JSValue* BitXOrNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToInt32(exec));
+}
+
+double BitXOrNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+bool BitXOrNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+int32_t BitXOrNode::evaluateToInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+uint32_t BitXOrNode::evaluateToUInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+void BitOrNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+int32_t BitOrNode::inlineEvaluateToInt32(ExecState* exec)
+{
+ int i1 = m_expr1->evaluateToInt32(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ int i2 = m_expr2->evaluateToInt32(exec);
+ return (i1 | i2);
+}
+
+JSValue* BitOrNode::evaluate(ExecState* exec)
+{
+ return jsNumber(inlineEvaluateToInt32(exec));
+}
+
+double BitOrNode::evaluateToNumber(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+bool BitOrNode::evaluateToBoolean(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+int32_t BitOrNode::evaluateToInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+uint32_t BitOrNode::evaluateToUInt32(ExecState* exec)
+{
+ return inlineEvaluateToInt32(exec);
+}
+
+// ------------------------------ Binary Logical Nodes ----------------------------
+
+void LogicalAndNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.11
+JSValue* LogicalAndNode::evaluate(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ bool b1 = v1->toBoolean(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ if (!b1)
+ return v1;
+ JSValue* v2 = m_expr2->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ return v2;
+}
+
+bool LogicalAndNode::evaluateToBoolean(ExecState* exec)
+{
+ bool b = m_expr1->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return b && m_expr2->evaluateToBoolean(exec);
+}
+
+void LogicalOrNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+JSValue* LogicalOrNode::evaluate(ExecState* exec)
+{
+ JSValue* v1 = m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ if (v1->toBoolean(exec))
+ return v1;
+ return m_expr2->evaluate(exec);
+}
+
+bool LogicalOrNode::evaluateToBoolean(ExecState* exec)
+{
+ bool b = m_expr1->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return b || m_expr2->evaluateToBoolean(exec);
+}
+
+// ------------------------------ ConditionalNode ------------------------------
+
+void ConditionalNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+ nodeStack.append(m_logical.get());
+}
+
+// ECMA 11.12
+JSValue* ConditionalNode::evaluate(ExecState* exec)
+{
+ bool b = m_logical->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ return b ? m_expr1->evaluate(exec) : m_expr2->evaluate(exec);
+}
+
+bool ConditionalNode::evaluateToBoolean(ExecState* exec)
+{
+ bool b = m_logical->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTIONBOOLEAN
+ return b ? m_expr1->evaluateToBoolean(exec) : m_expr2->evaluateToBoolean(exec);
+}
+
+double ConditionalNode::evaluateToNumber(ExecState* exec)
+{
+ bool b = m_logical->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return b ? m_expr1->evaluateToNumber(exec) : m_expr2->evaluateToNumber(exec);
+}
+
+int32_t ConditionalNode::evaluateToInt32(ExecState* exec)
+{
+ bool b = m_logical->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return b ? m_expr1->evaluateToInt32(exec) : m_expr2->evaluateToInt32(exec);
+}
+
+uint32_t ConditionalNode::evaluateToUInt32(ExecState* exec)
+{
+ bool b = m_logical->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTIONNUMBER
+ return b ? m_expr1->evaluateToUInt32(exec) : m_expr2->evaluateToUInt32(exec);
+}
+
+// ECMA 11.13
+
+static ALWAYS_INLINE JSValue* valueForReadModifyAssignment(ExecState* exec, JSValue* current, ExpressionNode* right, Operator oper) KJS_FAST_CALL;
+static ALWAYS_INLINE JSValue* valueForReadModifyAssignment(ExecState* exec, JSValue* current, ExpressionNode* right, Operator oper)
+{
+ JSValue* v;
+ int i1;
+ int i2;
+ unsigned int ui;
+ switch (oper) {
+ case OpMultEq:
+ v = jsNumber(current->toNumber(exec) * right->evaluateToNumber(exec));
+ break;
+ case OpDivEq:
+ v = jsNumber(current->toNumber(exec) / right->evaluateToNumber(exec));
+ break;
+ case OpPlusEq:
+ v = add(exec, current, right->evaluate(exec));
+ break;
+ case OpMinusEq:
+ v = jsNumber(current->toNumber(exec) - right->evaluateToNumber(exec));
+ break;
+ case OpLShift:
+ i1 = current->toInt32(exec);
+ i2 = right->evaluateToInt32(exec);
+ v = jsNumber(i1 << i2);
+ break;
+ case OpRShift:
+ i1 = current->toInt32(exec);
+ i2 = right->evaluateToInt32(exec);
+ v = jsNumber(i1 >> i2);
+ break;
+ case OpURShift:
+ ui = current->toUInt32(exec);
+ i2 = right->evaluateToInt32(exec);
+ v = jsNumber(ui >> i2);
+ break;
+ case OpAndEq:
+ i1 = current->toInt32(exec);
+ i2 = right->evaluateToInt32(exec);
+ v = jsNumber(i1 & i2);
+ break;
+ case OpXOrEq:
+ i1 = current->toInt32(exec);
+ i2 = right->evaluateToInt32(exec);
+ v = jsNumber(i1 ^ i2);
+ break;
+ case OpOrEq:
+ i1 = current->toInt32(exec);
+ i2 = right->evaluateToInt32(exec);
+ v = jsNumber(i1 | i2);
+ break;
+ case OpModEq: {
+ double d1 = current->toNumber(exec);
+ double d2 = right->evaluateToNumber(exec);
+ v = jsNumber(fmod(d1, d2));
+ }
+ break;
+ default:
+ ASSERT_NOT_REACHED();
+ v = jsUndefined();
+ }
+
+ return v;
+}
+
+// ------------------------------ ReadModifyResolveNode -----------------------------------
+
+void ReadModifyResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
+{
+ nodeStack.append(m_right.get());
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker()) {
+ if (isConstant(localStorage, index))
+ new (this) ReadModifyConstNode(index);
+ else
+ new (this) ReadModifyLocalVarNode(index);
+ }
+}
+
+// ------------------------------ AssignResolveNode -----------------------------------
+
+void AssignResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
+{
+ nodeStack.append(m_right.get());
+ size_t index = symbolTable.get(m_ident.ustring().rep());
+ if (index != missingSymbolMarker()) {
+ if (isConstant(localStorage, index))
+ new (this) AssignConstNode;
+ else
+ new (this) AssignLocalVarNode(index);
+ }
+}
+
+// ------------------------------ ReadModifyLocalVarNode -----------------------------------
+
+JSValue* ReadModifyLocalVarNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+
+ ASSERT(m_operator != OpEqual);
+ JSValue* v = valueForReadModifyAssignment(exec, exec->localStorage()[m_index].value, m_right.get(), m_operator);
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ // We can't store a pointer into localStorage() and use it throughout the function
+ // body, because valueForReadModifyAssignment() might cause an ActivationImp tear-off,
+ // changing the value of localStorage().
+
+ exec->localStorage()[m_index].value = v;
+ return v;
+}
+
+// ------------------------------ AssignLocalVarNode -----------------------------------
+
+JSValue* AssignLocalVarNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+ JSValue* v = m_right->evaluate(exec);
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ exec->localStorage()[m_index].value = v;
+
+ return v;
+}
+
+// ------------------------------ ReadModifyConstNode -----------------------------------
+
+JSValue* ReadModifyConstNode::evaluate(ExecState* exec)
+{
+ ASSERT(exec->variableObject() == exec->scopeChain().top());
+ JSValue* left = exec->localStorage()[m_index].value;
+ ASSERT(m_operator != OpEqual);
+ JSValue* result = valueForReadModifyAssignment(exec, left, m_right.get(), m_operator);
+ KJS_CHECKEXCEPTIONVALUE
+ return result;
+}
+
+// ------------------------------ AssignConstNode -----------------------------------
+
+JSValue* AssignConstNode::evaluate(ExecState* exec)
+{
+ return m_right->evaluate(exec);
+}
+
+JSValue* ReadModifyResolveNode::evaluate(ExecState* exec)
+{
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // We must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ JSObject* base;
+ do {
+ base = *iter;
+ if (base->getPropertySlot(exec, m_ident, slot)) {
+ // See the comment in PostIncResolveNode::evaluate().
+
+ base = *iter;
+ goto found;
+ }
+
+ ++iter;
+ } while (iter != end);
+
+ ASSERT(m_operator != OpEqual);
+ return throwUndefinedVariableError(exec, m_ident);
+
+found:
+ JSValue* v;
+
+ ASSERT(m_operator != OpEqual);
+ JSValue* v1 = slot.getValue(exec, base, m_ident);
+ KJS_CHECKEXCEPTIONVALUE
+ v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_operator);
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ // Since valueForReadModifyAssignment() might cause an ActivationImp tear-off,
+ // we need to get the base from the ScopeChainIterator again.
+
+ (*iter)->put(exec, m_ident, v);
+ return v;
+}
+
+JSValue* AssignResolveNode::evaluate(ExecState* exec)
+{
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // we must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ JSObject* base;
+ do {
+ base = *iter;
+ if (base->getPropertySlot(exec, m_ident, slot)) {
+ // See the comment in PostIncResolveNode::evaluate().
+
+ base = *iter;
+ goto found;
+ }
+
+ ++iter;
+ } while (iter != end);
+
+found:
+ JSValue* v = m_right->evaluate(exec);
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ base->put(exec, m_ident, v);
+ return v;
+}
+
+// ------------------------------ ReadModifyDotNode -----------------------------------
+
+void AssignDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_right.get());
+ nodeStack.append(m_base.get());
+}
+
+JSValue* AssignDotNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSObject* base = baseValue->toObject(exec);
+
+ JSValue* v = m_right->evaluate(exec);
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ base->put(exec, m_ident, v);
+ return v;
+}
+
+void ReadModifyDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_right.get());
+ nodeStack.append(m_base.get());
+}
+
+JSValue* ReadModifyDotNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSObject* base = baseValue->toObject(exec);
+
+ JSValue* v;
+
+ ASSERT(m_operator != OpEqual);
+ PropertySlot slot;
+ JSValue* v1 = base->getPropertySlot(exec, m_ident, slot) ? slot.getValue(exec, base, m_ident) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+ v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_operator);
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ base->put(exec, m_ident, v);
+ return v;
+}
+
+// ------------------------------ AssignErrorNode -----------------------------------
+
+JSValue* AssignErrorNode::evaluate(ExecState* exec)
+{
+ throwError(exec, ReferenceError, "Left side of assignment is not a reference.");
+ handleException(exec);
+ return jsUndefined();
+}
+
+// ------------------------------ AssignBracketNode -----------------------------------
+
+void AssignBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_right.get());
+ nodeStack.append(m_subscript.get());
+ nodeStack.append(m_base.get());
+}
+
+JSValue* AssignBracketNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* subscript = m_subscript->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* base = baseValue->toObject(exec);
+
+ uint32_t propertyIndex;
+ if (subscript->getUInt32(propertyIndex)) {
+ JSValue* v = m_right->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ base->put(exec, propertyIndex, v);
+ return v;
+ }
+
+ Identifier propertyName(subscript->toString(exec));
+ JSValue* v = m_right->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ base->put(exec, propertyName, v);
+ return v;
+}
+void ReadModifyBracketNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_right.get());
+ nodeStack.append(m_subscript.get());
+ nodeStack.append(m_base.get());
+}
+
+JSValue* ReadModifyBracketNode::evaluate(ExecState* exec)
+{
+ JSValue* baseValue = m_base->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ JSValue* subscript = m_subscript->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ JSObject* base = baseValue->toObject(exec);
+
+ uint32_t propertyIndex;
+ if (subscript->getUInt32(propertyIndex)) {
+ JSValue* v;
+ ASSERT(m_operator != OpEqual);
+ PropertySlot slot;
+ JSValue* v1 = base->getPropertySlot(exec, propertyIndex, slot) ? slot.getValue(exec, base, propertyIndex) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+ v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_operator);
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ base->put(exec, propertyIndex, v);
+ return v;
+ }
+
+ Identifier propertyName(subscript->toString(exec));
+ JSValue* v;
+
+ ASSERT(m_operator != OpEqual);
+ PropertySlot slot;
+ JSValue* v1 = base->getPropertySlot(exec, propertyName, slot) ? slot.getValue(exec, base, propertyName) : jsUndefined();
+ KJS_CHECKEXCEPTIONVALUE
+ v = valueForReadModifyAssignment(exec, v1, m_right.get(), m_operator);
+
+ KJS_CHECKEXCEPTIONVALUE
+
+ base->put(exec, propertyName, v);
+ return v;
+}
+
+// ------------------------------ CommaNode ------------------------------------
+
+void CommaNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 11.14
+JSValue* CommaNode::evaluate(ExecState* exec)
+{
+ m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ return m_expr2->evaluate(exec);
+}
+
+// ------------------------------ ConstDeclNode ----------------------------------
+
+ConstDeclNode::ConstDeclNode(const Identifier& ident, ExpressionNode* init)
+ : m_ident(ident)
+ , m_init(init)
+{
+}
+
+void ConstDeclNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_next)
+ nodeStack.append(m_next.get());
+ if (m_init)
+ nodeStack.append(m_init.get());
+}
+
+void ConstDeclNode::handleSlowCase(ExecState* exec, const ScopeChain& chain, JSValue* val)
+{
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // We must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ JSObject* base;
+
+ do {
+ base = *iter;
+ if (base->getPropertySlot(exec, m_ident, slot))
+ break;
+ ++iter;
+ } while (iter != end);
+
+ ASSERT(base->isActivationObject() || base->isGlobalObject());
+
+ static_cast<JSVariableObject*>(base)->initializeVariable(exec, m_ident, val, ReadOnly);
+}
+
+// ECMA 12.2
+inline void ConstDeclNode::evaluateSingle(ExecState* exec)
+{
+ ASSERT(exec->variableObject()->hasOwnProperty(exec, m_ident) || exec->codeType() == EvalCode); // Guaranteed by processDeclarations.
+ const ScopeChain& chain = exec->scopeChain();
+ JSVariableObject* variableObject = exec->variableObject();
+
+ ASSERT(!chain.isEmpty());
+
+ bool inGlobalScope = ++chain.begin() == chain.end();
+
+ if (m_init) {
+ if (inGlobalScope) {
+ JSValue* val = m_init->evaluate(exec);
+ unsigned attributes = ReadOnly;
+ if (exec->codeType() != EvalCode)
+ attributes |= DontDelete;
+ variableObject->initializeVariable(exec, m_ident, val, attributes);
+ } else {
+ JSValue* val = m_init->evaluate(exec);
+ KJS_CHECKEXCEPTIONVOID
+
+ // if the variable object is the top of the scope chain, then that must
+ // be where this variable is declared, processVarDecls would have put
+ // it there. Don't search the scope chain, to optimize this very common case.
+ if (chain.top() != variableObject)
+ return handleSlowCase(exec, chain, val);
+
+ variableObject->initializeVariable(exec, m_ident, val, ReadOnly);
+ }
+ }
+}
+
+JSValue* ConstDeclNode::evaluate(ExecState* exec)
+{
+ evaluateSingle(exec);
+
+ if (ConstDeclNode* n = m_next.get()) {
+ do {
+ n->evaluateSingle(exec);
+ KJS_CHECKEXCEPTIONVALUE
+ n = n->m_next.get();
+ } while (n);
+ }
+ return jsUndefined();
+}
+
+// ------------------------------ ConstStatementNode -----------------------------
+
+void ConstStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ ASSERT(m_next);
+ nodeStack.append(m_next.get());
+}
+
+// ECMA 12.2
+JSValue* ConstStatementNode::execute(ExecState* exec)
+{
+ m_next->evaluate(exec);
+ KJS_CHECKEXCEPTION
+
+ return exec->setNormalCompletion();
+}
+
+// ------------------------------ Helper functions for handling Vectors of StatementNode -------------------------------
+
+static inline void statementListPushFIFO(StatementVector& statements, DeclarationStacks::NodeStack& stack)
+{
+ StatementVector::iterator it = statements.end();
+ StatementVector::iterator begin = statements.begin();
+ while (it != begin) {
+ --it;
+ stack.append((*it).get());
+ }
+}
+
+static inline Node* statementListInitializeVariableAccessStack(StatementVector& statements, DeclarationStacks::NodeStack& stack)
+{
+ if (statements.isEmpty())
+ return 0;
+
+ StatementVector::iterator it = statements.end();
+ StatementVector::iterator begin = statements.begin();
+ StatementVector::iterator beginPlusOne = begin + 1;
+
+ while (it != beginPlusOne) {
+ --it;
+ stack.append((*it).get());
+ }
+
+ return (*begin).get();
+}
+
+static inline JSValue* statementListExecute(StatementVector& statements, ExecState* exec)
+{
+ JSValue* value = 0;
+ size_t size = statements.size();
+ for (size_t i = 0; i != size; ++i) {
+ JSValue* statementValue = statements[i]->execute(exec);
+ if (statementValue)
+ value = statementValue;
+ if (exec->completionType() != Normal)
+ return value;
+ }
+ return exec->setNormalCompletion(value);
+}
+
+// ------------------------------ BlockNode ------------------------------------
+
+BlockNode::BlockNode(SourceElements* children)
+{
+ if (children)
+ children->releaseContentsIntoVector(m_children);
+}
+
+void BlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ statementListPushFIFO(m_children, nodeStack);
+}
+
+// ECMA 12.1
+JSValue* BlockNode::execute(ExecState* exec)
+{
+ return statementListExecute(m_children, exec);
+}
+
+// ------------------------------ EmptyStatementNode ---------------------------
+
+// ECMA 12.3
+JSValue* EmptyStatementNode::execute(ExecState* exec)
+{
+ return exec->setNormalCompletion();
+}
+
+// ------------------------------ ExprStatementNode ----------------------------
+
+void ExprStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ ASSERT(m_expr);
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 12.4
+JSValue* ExprStatementNode::execute(ExecState* exec)
+{
+ JSValue* value = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTION
+
+ return exec->setNormalCompletion(value);
+}
+
+// ------------------------------ VarStatementNode ----------------------------
+
+void VarStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ ASSERT(m_expr);
+ nodeStack.append(m_expr.get());
+}
+
+JSValue* VarStatementNode::execute(ExecState* exec)
+{
+ m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTION
+
+ return exec->setNormalCompletion();
+}
+
+// ------------------------------ IfNode ---------------------------------------
+
+void IfNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_ifBlock.get());
+ nodeStack.append(m_condition.get());
+}
+
+// ECMA 12.5
+JSValue* IfNode::execute(ExecState* exec)
+{
+ bool b = m_condition->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTION
+
+ if (b)
+ return m_ifBlock->execute(exec);
+ return exec->setNormalCompletion();
+}
+
+void IfElseNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
+{
+ nodeStack.append(m_elseBlock.get());
+ IfNode::optimizeVariableAccess(symbolTable, localStorage, nodeStack);
+}
+
+// ECMA 12.5
+JSValue* IfElseNode::execute(ExecState* exec)
+{
+ bool b = m_condition->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTION
+
+ if (b)
+ return m_ifBlock->execute(exec);
+ return m_elseBlock->execute(exec);
+}
+
+// ------------------------------ DoWhileNode ----------------------------------
+
+void DoWhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_statement.get());
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 12.6.1
+JSValue* DoWhileNode::execute(ExecState* exec)
+{
+ JSValue* value = 0;
+
+ while (1) {
+ exec->pushIteration();
+ JSValue* statementValue = m_statement->execute(exec);
+ exec->popIteration();
+
+ if (exec->dynamicGlobalObject()->timedOut())
+ return exec->setInterruptedCompletion();
+
+ if (statementValue)
+ value = statementValue;
+
+ if (exec->completionType() != Normal) {
+ if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
+ goto continueDoWhileLoop;
+ if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
+ break;
+ return statementValue;
+ }
+
+ continueDoWhileLoop:
+ bool b = m_expr->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTION
+ if (!b)
+ break;
+ }
+
+ return exec->setNormalCompletion(value);
+}
+
+// ------------------------------ WhileNode ------------------------------------
+
+void WhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_statement.get());
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 12.6.2
+JSValue* WhileNode::execute(ExecState* exec)
+{
+ JSValue* value = 0;
+
+ while (1) {
+ bool b = m_expr->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTION
+ if (!b)
+ break;
+
+ exec->pushIteration();
+ JSValue* statementValue = m_statement->execute(exec);
+ exec->popIteration();
+
+ if (exec->dynamicGlobalObject()->timedOut())
+ return exec->setInterruptedCompletion();
+
+ if (statementValue)
+ value = statementValue;
+
+ if (exec->completionType() != Normal) {
+ if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
+ continue;
+ if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
+ break;
+ return statementValue;
+ }
+ }
+
+ return exec->setNormalCompletion(value);
+}
+
+// ------------------------------ ForNode --------------------------------------
+
+void ForNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_statement.get());
+ nodeStack.append(m_expr3.get());
+ nodeStack.append(m_expr2.get());
+ nodeStack.append(m_expr1.get());
+}
+
+// ECMA 12.6.3
+JSValue* ForNode::execute(ExecState* exec)
+{
+ JSValue* value = 0;
+
+ m_expr1->evaluate(exec);
+ KJS_CHECKEXCEPTION
+
+ while (1) {
+ bool b = m_expr2->evaluateToBoolean(exec);
+ KJS_CHECKEXCEPTION
+ if (!b)
+ break;
+
+ exec->pushIteration();
+ JSValue* statementValue = m_statement->execute(exec);
+ exec->popIteration();
+ if (statementValue)
+ value = statementValue;
+
+ if (exec->dynamicGlobalObject()->timedOut())
+ return exec->setInterruptedCompletion();
+
+ if (exec->completionType() != Normal) {
+ if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
+ goto continueForLoop;
+ if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
+ break;
+ return statementValue;
+ }
+
+ continueForLoop:
+ m_expr3->evaluate(exec);
+ KJS_CHECKEXCEPTION
+ }
+
+ return exec->setNormalCompletion(value);
+}
+
+// ------------------------------ ForInNode ------------------------------------
+
+ForInNode::ForInNode(ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
+ : m_init(0L)
+ , m_lexpr(l)
+ , m_expr(expr)
+ , m_statement(statement)
+ , m_identIsVarDecl(false)
+{
+}
+
+ForInNode::ForInNode(const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement)
+ : m_ident(ident)
+ , m_lexpr(new ResolveNode(ident))
+ , m_expr(expr)
+ , m_statement(statement)
+ , m_identIsVarDecl(true)
+{
+ if (in)
+ m_init = new AssignResolveNode(ident, in);
+ // for( var foo = bar in baz )
+}
+
+void ForInNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_statement.get());
+ nodeStack.append(m_expr.get());
+ nodeStack.append(m_lexpr.get());
+ if (m_init)
+ nodeStack.append(m_init.get());
+}
+
+// ECMA 12.6.4
+JSValue* ForInNode::execute(ExecState* exec)
+{
+ JSValue* value = 0;
+
+ if (m_init) {
+ m_init->evaluate(exec);
+ KJS_CHECKEXCEPTION
+ }
+
+ JSValue* e = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTION
+
+ // For Null and Undefined, we want to make sure not to go through
+ // the loop at all, because toObject will throw an exception.
+ if (e->isUndefinedOrNull())
+ return exec->setNormalCompletion();
+
+ JSObject* v = e->toObject(exec);
+ PropertyNameArray propertyNames;
+ v->getPropertyNames(exec, propertyNames);
+
+ PropertyNameArray::const_iterator end = propertyNames.end();
+ for (PropertyNameArray::const_iterator it = propertyNames.begin(); it != end; ++it) {
+ const Identifier& name = *it;
+ if (!v->hasProperty(exec, name))
+ continue;
+
+ JSValue* str = jsOwnedString(name.ustring());
+
+ if (m_lexpr->isResolveNode()) {
+ const Identifier& ident = static_cast<ResolveNode*>(m_lexpr.get())->identifier();
+
+ const ScopeChain& chain = exec->scopeChain();
+ ScopeChainIterator iter = chain.begin();
+ ScopeChainIterator end = chain.end();
+
+ // we must always have something in the scope chain
+ ASSERT(iter != end);
+
+ PropertySlot slot;
+ JSObject* o;
+ do {
+ o = *iter;
+ if (o->getPropertySlot(exec, ident, slot)) {
+ o->put(exec, ident, str);
+ break;
+ }
+ ++iter;
+ } while (iter != end);
+
+ if (iter == end)
+ o->put(exec, ident, str);
+ } else if (m_lexpr->isDotAccessorNode()) {
+ const Identifier& ident = static_cast<DotAccessorNode*>(m_lexpr.get())->identifier();
+ JSValue* v = static_cast<DotAccessorNode*>(m_lexpr.get())->base()->evaluate(exec);
+ KJS_CHECKEXCEPTION
+ JSObject* o = v->toObject(exec);
+
+ o->put(exec, ident, str);
+ } else {
+ ASSERT(m_lexpr->isBracketAccessorNode());
+ JSValue* v = static_cast<BracketAccessorNode*>(m_lexpr.get())->base()->evaluate(exec);
+ KJS_CHECKEXCEPTION
+ JSValue* v2 = static_cast<BracketAccessorNode*>(m_lexpr.get())->subscript()->evaluate(exec);
+ KJS_CHECKEXCEPTION
+ JSObject* o = v->toObject(exec);
+
+ uint32_t i;
+ if (v2->getUInt32(i))
+ o->put(exec, i, str);
+ o->put(exec, Identifier(v2->toString(exec)), str);
+ }
+
+ KJS_CHECKEXCEPTION
+
+ exec->pushIteration();
+ JSValue* statementValue = m_statement->execute(exec);
+ exec->popIteration();
+ if (statementValue)
+ value = statementValue;
+
+ if (exec->completionType() != Normal) {
+ if (exec->completionType() == Continue && m_labelStack.contains(exec->breakOrContinueTarget()))
+ continue;
+ if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
+ break;
+ return statementValue;
+ }
+ }
+
+ return exec->setNormalCompletion(value);
+}
+
+// ------------------------------ ContinueNode ---------------------------------
+
+// ECMA 12.7
+JSValue* ContinueNode::execute(ExecState* exec)
+{
+ if (m_ident.isEmpty() && !exec->inIteration())
+ return setErrorCompletion(exec, SyntaxError, "Invalid continue statement.");
+ if (!m_ident.isEmpty() && !exec->seenLabels().contains(m_ident))
+ return setErrorCompletion(exec, SyntaxError, "Label %s not found.", m_ident);
+ return exec->setContinueCompletion(&m_ident);
+}
+
+// ------------------------------ BreakNode ------------------------------------
+
+// ECMA 12.8
+JSValue* BreakNode::execute(ExecState* exec)
+{
+ if (m_ident.isEmpty() && !exec->inIteration() && !exec->inSwitch())
+ return setErrorCompletion(exec, SyntaxError, "Invalid break statement.");
+ if (!m_ident.isEmpty() && !exec->seenLabels().contains(m_ident))
+ return setErrorCompletion(exec, SyntaxError, "Label %s not found.");
+ return exec->setBreakCompletion(&m_ident);
+}
+
+// ------------------------------ ReturnNode -----------------------------------
+
+void ReturnNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_value)
+ nodeStack.append(m_value.get());
+}
+
+// ECMA 12.9
+JSValue* ReturnNode::execute(ExecState* exec)
+{
+ CodeType codeType = exec->codeType();
+ if (codeType != FunctionCode)
+ return setErrorCompletion(exec, SyntaxError, "Invalid return statement.");
+
+ if (!m_value)
+ return exec->setReturnValueCompletion(jsUndefined());
+
+ JSValue* v = m_value->evaluate(exec);
+ KJS_CHECKEXCEPTION
+
+ return exec->setReturnValueCompletion(v);
+}
+
+// ------------------------------ WithNode -------------------------------------
+
+void WithNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ // Can't optimize within statement because "with" introduces a dynamic scope.
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 12.10
+JSValue* WithNode::execute(ExecState* exec)
+{
+ JSValue* v = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTION
+ JSObject* o = v->toObject(exec);
+ KJS_CHECKEXCEPTION
+ exec->dynamicGlobalObject()->tearOffActivation(exec);
+ exec->pushScope(o);
+ JSValue* value = m_statement->execute(exec);
+ exec->popScope();
+
+ return value;
+}
+
+// ------------------------------ CaseClauseNode -------------------------------
+
+void CaseClauseNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_expr)
+ nodeStack.append(m_expr.get());
+ statementListPushFIFO(m_children, nodeStack);
+}
+
+// ECMA 12.11
+JSValue* CaseClauseNode::evaluate(ExecState* exec)
+{
+ JSValue* v = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTIONVALUE
+
+ return v;
+}
+
+// ECMA 12.11
+JSValue* CaseClauseNode::executeStatements(ExecState* exec)
+{
+ return statementListExecute(m_children, exec);
+}
+
+// ------------------------------ ClauseListNode -------------------------------
+
+void ClauseListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_next)
+ nodeStack.append(m_next.get());
+ nodeStack.append(m_clause.get());
+}
+
+// ------------------------------ CaseBlockNode --------------------------------
+
+CaseBlockNode::CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2)
+ : m_list1(list1)
+ , m_defaultClause(defaultClause)
+ , m_list2(list2)
+{
+}
+
+void CaseBlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ if (m_list2)
+ nodeStack.append(m_list2.get());
+ if (m_defaultClause)
+ nodeStack.append(m_defaultClause.get());
+ if (m_list1)
+ nodeStack.append(m_list1.get());
+}
+
+// ECMA 12.11
+JSValue* CaseBlockNode::executeBlock(ExecState* exec, JSValue* input)
+{
+ ClauseListNode* a = m_list1.get();
+ while (a) {
+ CaseClauseNode* clause = a->getClause();
+ a = a->getNext();
+ JSValue* v = clause->evaluate(exec);
+ KJS_CHECKEXCEPTION
+ if (strictEqual(exec, input, v)) {
+ JSValue* res = clause->executeStatements(exec);
+ if (exec->completionType() != Normal)
+ return res;
+ for (; a; a = a->getNext()) {
+ JSValue* res = a->getClause()->executeStatements(exec);
+ if (exec->completionType() != Normal)
+ return res;
+ }
+ break;
+ }
+ }
+
+ ClauseListNode* b = m_list2.get();
+ while (b) {
+ CaseClauseNode* clause = b->getClause();
+ b = b->getNext();
+ JSValue* v = clause->evaluate(exec);
+ KJS_CHECKEXCEPTION
+ if (strictEqual(exec, input, v)) {
+ JSValue* res = clause->executeStatements(exec);
+ if (exec->completionType() != Normal)
+ return res;
+ goto step18;
+ }
+ }
+
+ // default clause
+ if (m_defaultClause) {
+ JSValue* res = m_defaultClause->executeStatements(exec);
+ if (exec->completionType() != Normal)
+ return res;
+ }
+ b = m_list2.get();
+step18:
+ while (b) {
+ CaseClauseNode* clause = b->getClause();
+ JSValue* res = clause->executeStatements(exec);
+ if (exec->completionType() != Normal)
+ return res;
+ b = b->getNext();
+ }
+
+ // bail out on error
+ KJS_CHECKEXCEPTION
+
+ return exec->setNormalCompletion();
+}
+
+// ------------------------------ SwitchNode -----------------------------------
+
+void SwitchNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_block.get());
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 12.11
+JSValue* SwitchNode::execute(ExecState* exec)
+{
+ JSValue* v = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTION
+
+ exec->pushSwitch();
+ JSValue* result = m_block->executeBlock(exec, v);
+ exec->popSwitch();
+
+ if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
+ exec->setCompletionType(Normal);
+ return result;
+}
+
+// ------------------------------ LabelNode ------------------------------------
+
+void LabelNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_statement.get());
+}
+
+// ECMA 12.12
+JSValue* LabelNode::execute(ExecState* exec)
+{
+ if (!exec->seenLabels().push(m_label))
+ return setErrorCompletion(exec, SyntaxError, "Duplicated label %s found.", m_label);
+ JSValue* result = m_statement->execute(exec);
+ exec->seenLabels().pop();
+
+ if (exec->completionType() == Break && exec->breakOrContinueTarget() == m_label)
+ exec->setCompletionType(Normal);
+ return result;
+}
+
+// ------------------------------ ThrowNode ------------------------------------
+
+void ThrowNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ nodeStack.append(m_expr.get());
+}
+
+// ECMA 12.13
+JSValue* ThrowNode::execute(ExecState* exec)
+{
+ JSValue* v = m_expr->evaluate(exec);
+ KJS_CHECKEXCEPTION
+
+ handleException(exec, v);
+ return exec->setThrowCompletion(v);
+}
+
+// ------------------------------ TryNode --------------------------------------
+
+void TryNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+{
+ // Can't optimize within catchBlock because "catch" introduces a dynamic scope.
+ if (m_finallyBlock)
+ nodeStack.append(m_finallyBlock.get());
+ nodeStack.append(m_tryBlock.get());
+}
+
+// ECMA 12.14
+JSValue* TryNode::execute(ExecState* exec)
+{
+ JSValue* result = m_tryBlock->execute(exec);
+
+ if (m_catchBlock && exec->completionType() == Throw) {
+ JSObject* obj = new JSObject;
+ obj->putDirect(m_exceptionIdent, result, DontDelete);
+ exec->dynamicGlobalObject()->tearOffActivation(exec);
+ exec->pushScope(obj);
+ result = m_catchBlock->execute(exec);
+ exec->popScope();
+ }
+
+ if (m_finallyBlock) {
+ ComplType savedCompletionType = exec->completionType();
+ JSValue* finallyResult = m_finallyBlock->execute(exec);
+ if (exec->completionType() != Normal)
+ result = finallyResult;
+ else
+ exec->setCompletionType(savedCompletionType);
+ }
+
+ return result;
+}
+
+// ------------------------------ FunctionBodyNode -----------------------------
+
+ScopeNode::ScopeNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
+ : BlockNode(children)
+ , m_sourceURL(parser().sourceURL())
+ , m_sourceId(parser().sourceId())
+{
+ if (varStack)
+ m_varStack = *varStack;
+ if (funcStack)
+ m_functionStack = *funcStack;
+}
+
+// ------------------------------ ProgramNode -----------------------------
+
+ProgramNode::ProgramNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
+ : ScopeNode(children, varStack, funcStack)
+{
+}
+
+ProgramNode* ProgramNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
+{
+ return new ProgramNode(children, varStack, funcStack);
+}
+
+// ------------------------------ EvalNode -----------------------------
+
+EvalNode::EvalNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
+ : ScopeNode(children, varStack, funcStack)
+{
+}
+
+EvalNode* EvalNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
+{
+ return new EvalNode(children, varStack, funcStack);
+}
+
+// ------------------------------ FunctionBodyNode -----------------------------
+
+FunctionBodyNode::FunctionBodyNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
+ : ScopeNode(children, varStack, funcStack)
+ , m_initialized(false)
+{
+}
+
+FunctionBodyNode* FunctionBodyNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
+{
+ if (Debugger::debuggersPresent)
+ return new FunctionBodyNodeWithDebuggerHooks(children, varStack, funcStack);
+ return new FunctionBodyNode(children, varStack, funcStack);
+}
+
+void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
+{
+ SymbolTable& symbolTable = exec->variableObject()->symbolTable();
+ ASSERT(symbolTable.isEmpty());
+
+ size_t localStorageIndex = 0;
+
+ // Order must match the order in processDeclarations.
+
+ for (size_t i = 0, size = m_parameters.size(); i < size; ++i, ++localStorageIndex) {
+ UString::Rep* rep = m_parameters[i].ustring().rep();
+ symbolTable.set(rep, localStorageIndex);
+ }
+
+ for (size_t i = 0, size = m_functionStack.size(); i < size; ++i, ++localStorageIndex) {
+ UString::Rep* rep = m_functionStack[i]->m_ident.ustring().rep();
+ symbolTable.set(rep, localStorageIndex);
+ }
+
+ for (size_t i = 0, size = m_varStack.size(); i < size; ++i, ++localStorageIndex) {
+ Identifier& ident = m_varStack[i].first;
+ if (ident == exec->propertyNames().arguments)
+ continue;
+ symbolTable.add(ident.ustring().rep(), localStorageIndex);
+ }
+}
+
+void ProgramNode::initializeSymbolTable(ExecState* exec)
+{
+ // If a previous script defined a symbol with the same name as one of our
+ // symbols, to avoid breaking previously optimized nodes, we need to reuse
+ // the symbol's existing storage index. So, we can't be as efficient as
+ // FunctionBodyNode::initializeSymbolTable, which knows that no bindings
+ // have yet been made.
+
+ JSVariableObject* variableObject = exec->variableObject();
+ SymbolTable& symbolTable = variableObject->symbolTable();
+
+ size_t localStorageIndex = symbolTable.size();
+ size_t size;
+
+ // Order must match the order in processDeclarations.
+
+ size = m_functionStack.size();
+ m_functionIndexes.resize(size);
+ for (size_t i = 0; i < size; ++i) {
+ UString::Rep* rep = m_functionStack[i]->m_ident.ustring().rep();
+ pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
+ m_functionIndexes[i] = result.first->second;
+ if (result.second)
+ ++localStorageIndex;
+ }
+
+ size = m_varStack.size();
+ m_varIndexes.resize(size);
+ for (size_t i = 0; i < size; ++i) {
+ const Identifier& ident = m_varStack[i].first;
+ if (variableObject->hasProperty(exec, ident)) {
+ m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
+ continue;
+ }
+
+ UString::Rep* rep = ident.ustring().rep();
+ pair<SymbolTable::iterator, bool> result = symbolTable.add(rep, localStorageIndex);
+ if (!result.second) {
+ m_varIndexes[i] = missingSymbolMarker(); // Signal not to initialize this declaration.
+ continue;
+ }
+
+ m_varIndexes[i] = result.first->second;
+ ++localStorageIndex;
+ }
+}
+
+void ScopeNode::optimizeVariableAccess(ExecState* exec)
+{
+ NodeStack nodeStack;
+ Node* node = statementListInitializeVariableAccessStack(m_children, nodeStack);
+ if (!node)
+ return;
+
+ const SymbolTable& symbolTable = exec->variableObject()->symbolTable();
+ const LocalStorage& localStorage = exec->variableObject()->localStorage();
+ while (true) {
+ node->optimizeVariableAccess(symbolTable, localStorage, nodeStack);
+
+ size_t size = nodeStack.size();
+ if (!size)
+ break;
+ --size;
+ node = nodeStack[size];
+ nodeStack.shrink(size);
+ }
+}
+
+void FunctionBodyNode::processDeclarations(ExecState* exec)
+{
+ if (!m_initialized)
+ initializeSymbolTable(exec);
+
+ if (!m_functionStack.isEmpty())
+ exec->dynamicGlobalObject()->tearOffActivation(exec);
+
+ LocalStorage& localStorage = exec->variableObject()->localStorage();
+
+ // We can't just resize localStorage here because that would temporarily
+ // leave uninitialized entries, which would crash GC during the mark phase.
+ size_t totalSize = m_varStack.size() + m_parameters.size() + m_functionStack.size();
+ if (totalSize > localStorage.capacity()) // Doing this check inline avoids function call overhead.
+ localStorage.reserveCapacity(totalSize);
+
+ int minAttributes = DontDelete;
+
+ // In order for our localStorage indexes to be correct, we must match the
+ // order of addition in initializeSymbolTable().
+
+ const List& args = *exec->arguments();
+ for (size_t i = 0, size = m_parameters.size(); i < size; ++i)
+ localStorage.uncheckedAppend(LocalStorageEntry(args[i], DontDelete));
+
+ for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
+ FuncDeclNode* node = m_functionStack[i];
+ localStorage.uncheckedAppend(LocalStorageEntry(node->makeFunction(exec), minAttributes));
+ }
+
+ for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
+ int attributes = minAttributes;
+ if (m_varStack[i].second & DeclarationStacks::IsConstant)
+ attributes |= ReadOnly;
+ localStorage.uncheckedAppend(LocalStorageEntry(jsUndefined(), attributes));
+ }
+
+ if (!m_initialized) {
+ optimizeVariableAccess(exec);
+ m_initialized = true;
+ }
+}
+
+static void gccIsCrazy() KJS_FAST_CALL;
+static void gccIsCrazy()
+{
+}
+
+void ProgramNode::processDeclarations(ExecState* exec)
+{
+ // If you remove this call, some SunSpider tests, including
+ // bitops-nsieve-bits.js, will regress substantially on Mac, due to a ~40%
+ // increase in L2 cache misses. FIXME: <rdar://problem/5657439> WTF?
+ gccIsCrazy();
+
+ initializeSymbolTable(exec);
+
+ LocalStorage& localStorage = exec->variableObject()->localStorage();
+
+ // We can't just resize localStorage here because that would temporarily
+ // leave uninitialized entries, which would crash GC during the mark phase.
+ localStorage.reserveCapacity(localStorage.size() + m_varStack.size() + m_functionStack.size());
+
+ int minAttributes = DontDelete;
+
+ // In order for our localStorage indexes to be correct, we must match the
+ // order of addition in initializeSymbolTable().
+
+ for (size_t i = 0, size = m_functionStack.size(); i < size; ++i) {
+ FuncDeclNode* node = m_functionStack[i];
+ LocalStorageEntry entry = LocalStorageEntry(node->makeFunction(exec), minAttributes);
+ size_t index = m_functionIndexes[i];
+
+ if (index == localStorage.size())
+ localStorage.uncheckedAppend(entry);
+ else {
+ ASSERT(index < localStorage.size());
+ localStorage[index] = entry;
+ }
+ }
+
+ for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
+ size_t index = m_varIndexes[i];
+ if (index == missingSymbolMarker())
+ continue;
+
+ int attributes = minAttributes;
+ if (m_varStack[i].second & DeclarationStacks::IsConstant)
+ attributes |= ReadOnly;
+ LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
+
+ ASSERT(index == localStorage.size());
+ localStorage.uncheckedAppend(entry);
+ }
+
+ optimizeVariableAccess(exec);
+}
+
+void EvalNode::processDeclarations(ExecState* exec)
+{
+ // We could optimize access to pre-existing symbols here, but SunSpider
+ // reports that to be a net loss.
+
+ size_t i;
+ size_t size;
+
+ JSVariableObject* variableObject = exec->variableObject();
+
+ for (i = 0, size = m_varStack.size(); i < size; ++i) {
+ Identifier& ident = m_varStack[i].first;
+ if (variableObject->hasProperty(exec, ident))
+ continue;
+ int attributes = 0;
+ if (m_varStack[i].second & DeclarationStacks::IsConstant)
+ attributes = ReadOnly;
+ variableObject->initializeVariable(exec, ident, jsUndefined(), attributes);
+ }
+
+ for (i = 0, size = m_functionStack.size(); i < size; ++i) {
+ FuncDeclNode* funcDecl = m_functionStack[i];
+ variableObject->initializeVariable(exec, funcDecl->m_ident, funcDecl->makeFunction(exec), 0);
+ }
+}
+
+UString FunctionBodyNode::paramString() const
+{
+ UString s("");
+ size_t count = m_parameters.size();
+ for (size_t pos = 0; pos < count; ++pos) {
+ if (!s.isEmpty())
+ s += ", ";
+ s += m_parameters[pos].ustring();
+ }
+
+ return s;
+}
+
+JSValue* ProgramNode::execute(ExecState* exec)
+{
+ processDeclarations(exec);
+ return ScopeNode::execute(exec);
+}
+
+JSValue* EvalNode::execute(ExecState* exec)
+{
+ processDeclarations(exec);
+ return ScopeNode::execute(exec);
+}
+
+JSValue* FunctionBodyNode::execute(ExecState* exec)
+{
+ processDeclarations(exec);
+ return ScopeNode::execute(exec);
+}
+
+// ------------------------------ FunctionBodyNodeWithDebuggerHooks ---------------------------------
+
+FunctionBodyNodeWithDebuggerHooks::FunctionBodyNodeWithDebuggerHooks(SourceElements* children, DeclarationStacks::VarStack* varStack, DeclarationStacks::FunctionStack* funcStack)
+ : FunctionBodyNode(children, varStack, funcStack)
+{
+}
+
+JSValue* FunctionBodyNodeWithDebuggerHooks::execute(ExecState* exec)
+{
+ if (Debugger* dbg = exec->dynamicGlobalObject()->debugger()) {
+ if (!dbg->callEvent(exec, sourceId(), lineNo(), exec->function(), *exec->arguments()))
+ return exec->setInterruptedCompletion();
+ }
+
+ JSValue* result = FunctionBodyNode::execute(exec);
+
+ if (Debugger* dbg = exec->dynamicGlobalObject()->debugger()) {
+ if (exec->completionType() == Throw)
+ exec->setException(result);
+ if (!dbg->returnEvent(exec, sourceId(), lineNo(), exec->function()))
+ return exec->setInterruptedCompletion();
+ }
+
+ return result;
+}
+
+// ------------------------------ FuncDeclNode ---------------------------------
+
+void FuncDeclNode::addParams()
+{
+ for (ParameterNode* p = m_parameter.get(); p; p = p->nextParam())
+ m_body->parameters().append(p->ident());
+}
+
+FunctionImp* FuncDeclNode::makeFunction(ExecState* exec)
+{
+ FunctionImp* func = new FunctionImp(exec, m_ident, m_body.get(), exec->scopeChain());
+
+ JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
+ proto->putDirect(exec->propertyNames().constructor, func, DontEnum);
+ func->putDirect(exec->propertyNames().prototype, proto, DontDelete);
+ func->putDirect(exec->propertyNames().length, jsNumber(m_body->parameters().size()), ReadOnly | DontDelete | DontEnum);
+ return func;
+}
+
+JSValue* FuncDeclNode::execute(ExecState* exec)
+{
+ return exec->setNormalCompletion();
+}
+
+// ------------------------------ FuncExprNode ---------------------------------
+
+// ECMA 13
+void FuncExprNode::addParams()
+{
+ for (ParameterNode* p = m_parameter.get(); p; p = p->nextParam())
+ m_body->parameters().append(p->ident());
+}
+
+JSValue* FuncExprNode::evaluate(ExecState* exec)
+{
+ exec->dynamicGlobalObject()->tearOffActivation(exec);
+
+ bool named = !m_ident.isNull();
+ JSObject* functionScopeObject = 0;
+
+ if (named) {
+ // named FunctionExpressions can recursively call themselves,
+ // but they won't register with the current scope chain and should
+ // be contained as single property in an anonymous object.
+ functionScopeObject = new JSObject;
+ exec->pushScope(functionScopeObject);
+ }
+
+ FunctionImp* func = new FunctionImp(exec, m_ident, m_body.get(), exec->scopeChain());
+ JSObject* proto = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
+ proto->putDirect(exec->propertyNames().constructor, func, DontEnum);
+ func->putDirect(exec->propertyNames().prototype, proto, DontDelete);
+
+ if (named) {
+ functionScopeObject->putDirect(m_ident, func, ReadOnly | (exec->codeType() == EvalCode ? 0 : DontDelete));
+ exec->popScope();
+ }
+
+ return func;
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/nodes.h b/JavaScriptCore/kjs/nodes.h
new file mode 100644
index 0000000..f366557
--- /dev/null
+++ b/JavaScriptCore/kjs/nodes.h
@@ -0,0 +1,2907 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ * Copyright (C) 2007 Maks Orlovich
+ * 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.
+ *
+ */
+
+#ifndef NODES_H_
+#define NODES_H_
+
+#include "internal.h"
+#include "regexp.h"
+#include "SymbolTable.h"
+#include <wtf/ListRefPtr.h>
+#include <wtf/MathExtras.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/Vector.h>
+
+#if PLATFORM(X86) && COMPILER(GCC)
+#define KJS_FAST_CALL __attribute__((regparm(3)))
+#else
+#define KJS_FAST_CALL
+#endif
+
+namespace KJS {
+
+ class ConstDeclNode;
+ class FuncDeclNode;
+ class Node;
+ class PropertyListNode;
+ class SourceStream;
+
+ enum Operator {
+ OpEqual,
+ OpPlusEq,
+ OpMinusEq,
+ OpMultEq,
+ OpDivEq,
+ OpPlusPlus,
+ OpMinusMinus,
+ OpAndEq,
+ OpXOrEq,
+ OpOrEq,
+ OpModEq,
+ OpLShift,
+ OpRShift,
+ OpURShift,
+ };
+
+ enum Precedence {
+ PrecPrimary,
+ PrecMember,
+ PrecCall,
+ PrecLeftHandSide,
+ PrecPostfix,
+ PrecUnary,
+ PrecMultiplicitave,
+ PrecAdditive,
+ PrecShift,
+ PrecRelational,
+ PrecEquality,
+ PrecBitwiseAnd,
+ PrecBitwiseXor,
+ PrecBitwiseOr,
+ PrecLogicalAnd,
+ PrecLogicalOr,
+ PrecConditional,
+ PrecAssignment,
+ PrecExpression
+ };
+
+ struct DeclarationStacks {
+ typedef Vector<Node*, 16> NodeStack;
+ enum { IsConstant = 1, HasInitializer = 2 } VarAttrs;
+ typedef Vector<std::pair<Identifier, unsigned>, 16> VarStack;
+ typedef Vector<FuncDeclNode*, 16> FunctionStack;
+
+ DeclarationStacks(ExecState* e, NodeStack& n, VarStack& v, FunctionStack& f)
+ : exec(e)
+ , nodeStack(n)
+ , varStack(v)
+ , functionStack(f)
+ {
+ }
+
+ ExecState* exec;
+ NodeStack& nodeStack;
+ VarStack& varStack;
+ FunctionStack& functionStack;
+ };
+
+ class ParserRefCounted : Noncopyable {
+ protected:
+ ParserRefCounted() KJS_FAST_CALL;
+ ParserRefCounted(PlacementNewAdoptType) KJS_FAST_CALL
+ {
+ }
+
+ public:
+ void ref() KJS_FAST_CALL;
+ void deref() KJS_FAST_CALL;
+ unsigned refcount() KJS_FAST_CALL;
+
+ static void deleteNewObjects() KJS_FAST_CALL;
+
+ virtual ~ParserRefCounted();
+ };
+
+ class Node : public ParserRefCounted {
+ public:
+ typedef DeclarationStacks::NodeStack NodeStack;
+ typedef DeclarationStacks::VarStack VarStack;
+ typedef DeclarationStacks::FunctionStack FunctionStack;
+
+ Node() KJS_FAST_CALL;
+ Node(PlacementNewAdoptType placementAdopt) KJS_FAST_CALL
+ : ParserRefCounted(placementAdopt)
+ {
+ }
+
+ UString toString() const KJS_FAST_CALL;
+ int lineNo() const KJS_FAST_CALL { return m_line; }
+
+ // Serialization.
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL = 0;
+ virtual Precedence precedence() const = 0;
+ virtual bool needsParensIfLeftmost() const { return false; }
+
+ // Used for iterative, depth-first traversal of the node tree. Does not cross function call boundaries.
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL { }
+
+ protected:
+ Node(JSType) KJS_FAST_CALL; // used by ExpressionNode
+
+ // for use in execute()
+ JSValue* setErrorCompletion(ExecState*, ErrorType, const char* msg) KJS_FAST_CALL;
+ JSValue* setErrorCompletion(ExecState*, ErrorType, const char* msg, const Identifier&) KJS_FAST_CALL;
+
+ // for use in evaluate()
+ JSValue* throwError(ExecState*, ErrorType, const char* msg) KJS_FAST_CALL;
+ JSValue* throwError(ExecState*, ErrorType, const char* msg, const char*) KJS_FAST_CALL;
+ JSValue* throwError(ExecState*, ErrorType, const char* msg, JSValue*, Node*) KJS_FAST_CALL;
+ JSValue* throwError(ExecState*, ErrorType, const char* msg, const Identifier&) KJS_FAST_CALL;
+ JSValue* throwError(ExecState*, ErrorType, const char* msg, JSValue*, const Identifier&) KJS_FAST_CALL;
+ JSValue* throwError(ExecState*, ErrorType, const char* msg, JSValue*, Node*, Node*) KJS_FAST_CALL;
+ JSValue* throwError(ExecState*, ErrorType, const char* msg, JSValue*, Node*, const Identifier&) KJS_FAST_CALL;
+
+ JSValue* throwUndefinedVariableError(ExecState*, const Identifier&) KJS_FAST_CALL;
+
+ void handleException(ExecState*) KJS_FAST_CALL;
+ void handleException(ExecState*, JSValue*) KJS_FAST_CALL;
+
+ // for use in execute()
+ JSValue* rethrowException(ExecState*) KJS_FAST_CALL;
+
+ int m_line : 28;
+ unsigned m_expectedReturnType : 3; // JSType
+ };
+
+ class ExpressionNode : public Node {
+ public:
+ ExpressionNode() KJS_FAST_CALL : Node() {}
+ ExpressionNode(JSType expectedReturn) KJS_FAST_CALL
+ : Node(expectedReturn)
+ {
+ }
+
+ // Special constructor for cases where we overwrite an object in place.
+ ExpressionNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : Node(PlacementNewAdopt)
+ {
+ }
+
+ virtual bool isNumber() const KJS_FAST_CALL { return false; }
+ virtual bool isLocation() const KJS_FAST_CALL { return false; }
+ virtual bool isResolveNode() const KJS_FAST_CALL { return false; }
+ virtual bool isBracketAccessorNode() const KJS_FAST_CALL { return false; }
+ virtual bool isDotAccessorNode() const KJS_FAST_CALL { return false; }
+
+ JSType expectedReturnType() const KJS_FAST_CALL { return static_cast<JSType>(m_expectedReturnType); }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL = 0;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+
+ // Used to optimize those nodes that do extra work when returning a result, even if the result has no semantic relevance
+ virtual void optimizeForUnnecessaryResult() { }
+ };
+
+ class StatementNode : public Node {
+ public:
+ StatementNode() KJS_FAST_CALL;
+ void setLoc(int line0, int line1) KJS_FAST_CALL;
+ int firstLine() const KJS_FAST_CALL { return lineNo(); }
+ int lastLine() const KJS_FAST_CALL { return m_lastLine; }
+ virtual JSValue* execute(ExecState *exec) KJS_FAST_CALL = 0;
+ virtual void pushLabel(const Identifier& ident) KJS_FAST_CALL { m_labelStack.push(ident); }
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+ virtual bool isEmptyStatement() const KJS_FAST_CALL { return false; }
+
+ protected:
+ LabelStack m_labelStack;
+
+ private:
+ int m_lastLine;
+ };
+
+ class NullNode : public ExpressionNode {
+ public:
+ NullNode() KJS_FAST_CALL : ExpressionNode(NullType) {}
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+ };
+
+ class FalseNode : public ExpressionNode {
+ public:
+ FalseNode() KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL { return false; }
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+ };
+
+ class TrueNode : public ExpressionNode {
+ public:
+ TrueNode() KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL { return true; }
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+ };
+
+ class PlaceholderTrueNode : public TrueNode {
+ public:
+ // Like TrueNode, but does not serialize as "true".
+ PlaceholderTrueNode() KJS_FAST_CALL
+ : TrueNode()
+ {
+ }
+
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ };
+
+ class NumberNode : public ExpressionNode {
+ public:
+ NumberNode(double v) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_double(v)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return signbit(m_double) ? PrecUnary : PrecPrimary; }
+
+ virtual bool isNumber() const KJS_FAST_CALL { return true; }
+ double value() const KJS_FAST_CALL { return m_double; }
+ virtual void setValue(double d) KJS_FAST_CALL { m_double = d; }
+
+ protected:
+ double m_double;
+ };
+
+ class ImmediateNumberNode : public NumberNode {
+ public:
+ ImmediateNumberNode(JSValue* v, double d) KJS_FAST_CALL
+ : NumberNode(d)
+ , m_value(v)
+ {
+ ASSERT(v == JSImmediate::from(d));
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+
+ virtual void setValue(double d) KJS_FAST_CALL { m_double = d; m_value = JSImmediate::from(d); ASSERT(m_value); }
+
+ private:
+ JSValue* m_value; // This is never a JSCell, only JSImmediate, thus no ProtectedPtr
+ };
+
+ class StringNode : public ExpressionNode {
+ public:
+ StringNode(const UString* v) KJS_FAST_CALL
+ : ExpressionNode(StringType)
+ , m_value(*v)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+
+ private:
+ UString m_value;
+ };
+
+ class RegExpNode : public ExpressionNode {
+ public:
+ RegExpNode(const UString& pattern, const UString& flags) KJS_FAST_CALL
+ : m_regExp(RegExp::create(pattern, flags))
+ {
+ }
+
+ JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+
+ private:
+ RefPtr<RegExp> m_regExp;
+ };
+
+ class ThisNode : public ExpressionNode {
+ public:
+ ThisNode() KJS_FAST_CALL
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+ };
+
+ class ResolveNode : public ExpressionNode {
+ public:
+ ResolveNode(const Identifier& ident) KJS_FAST_CALL
+ : m_ident(ident)
+ {
+ }
+
+ // Special constructor for cases where we overwrite an object in place.
+ ResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : ExpressionNode(PlacementNewAdopt)
+ , m_ident(PlacementNewAdopt)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+
+ virtual bool isLocation() const KJS_FAST_CALL { return true; }
+ virtual bool isResolveNode() const KJS_FAST_CALL { return true; }
+ const Identifier& identifier() const KJS_FAST_CALL { return m_ident; }
+
+ protected:
+ ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
+ Identifier m_ident;
+ size_t m_index; // Used by LocalVarAccessNode.
+ };
+
+ class LocalVarAccessNode : public ResolveNode {
+ public:
+ // Overwrites a ResolveNode in place.
+ LocalVarAccessNode(size_t i) KJS_FAST_CALL
+ : ResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+
+ private:
+ ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
+ };
+
+ class ElementNode : public Node {
+ public:
+ ElementNode(int elision, ExpressionNode* node) KJS_FAST_CALL
+ : m_elision(elision)
+ , m_node(node)
+ {
+ }
+
+ ElementNode(ElementNode* l, int elision, ExpressionNode* node) KJS_FAST_CALL
+ : m_elision(elision)
+ , m_node(node)
+ {
+ l->m_next = this;
+ }
+
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+
+ PassRefPtr<ElementNode> releaseNext() KJS_FAST_CALL { return m_next.release(); }
+
+ JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+
+ private:
+ friend class ArrayNode;
+ ListRefPtr<ElementNode> m_next;
+ int m_elision;
+ RefPtr<ExpressionNode> m_node;
+ };
+
+ class ArrayNode : public ExpressionNode {
+ public:
+ ArrayNode(int elision) KJS_FAST_CALL
+ : m_elision(elision)
+ , m_optional(true)
+ {
+ }
+
+ ArrayNode(ElementNode* element) KJS_FAST_CALL
+ : m_element(element)
+ , m_elision(0)
+ , m_optional(false)
+ {
+ }
+
+ ArrayNode(int elision, ElementNode* element) KJS_FAST_CALL
+ : m_element(element)
+ , m_elision(elision)
+ , m_optional(true)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+
+ private:
+ RefPtr<ElementNode> m_element;
+ int m_elision;
+ bool m_optional;
+ };
+
+ class PropertyNode : public Node {
+ public:
+ enum Type { Constant, Getter, Setter };
+
+ PropertyNode(const Identifier& name, ExpressionNode* assign, Type type) KJS_FAST_CALL
+ : m_name(name)
+ , m_assign(assign)
+ , m_type(type)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+
+ JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ const Identifier& name() const { return m_name; }
+
+ private:
+ friend class PropertyListNode;
+ Identifier m_name;
+ RefPtr<ExpressionNode> m_assign;
+ Type m_type;
+ };
+
+ class PropertyListNode : public Node {
+ public:
+ PropertyListNode(PropertyNode* node) KJS_FAST_CALL
+ : m_node(node)
+ {
+ }
+
+ PropertyListNode(PropertyNode* node, PropertyListNode* list) KJS_FAST_CALL
+ : m_node(node)
+ {
+ list->m_next = this;
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+
+ JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ PassRefPtr<PropertyListNode> releaseNext() KJS_FAST_CALL { return m_next.release(); }
+
+ private:
+ friend class ObjectLiteralNode;
+ RefPtr<PropertyNode> m_node;
+ ListRefPtr<PropertyListNode> m_next;
+ };
+
+ class ObjectLiteralNode : public ExpressionNode {
+ public:
+ ObjectLiteralNode() KJS_FAST_CALL
+ {
+ }
+
+ ObjectLiteralNode(PropertyListNode* list) KJS_FAST_CALL
+ : m_list(list)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+ virtual bool needsParensIfLeftmost() const { return true; }
+
+ private:
+ RefPtr<PropertyListNode> m_list;
+ };
+
+ class BracketAccessorNode : public ExpressionNode {
+ public:
+ BracketAccessorNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
+ : m_base(base)
+ , m_subscript(subscript)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecMember; }
+
+ virtual bool isLocation() const KJS_FAST_CALL { return true; }
+ virtual bool isBracketAccessorNode() const KJS_FAST_CALL { return true; }
+ ExpressionNode* base() KJS_FAST_CALL { return m_base.get(); }
+ ExpressionNode* subscript() KJS_FAST_CALL { return m_subscript.get(); }
+
+ private:
+ ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
+
+ RefPtr<ExpressionNode> m_base;
+ RefPtr<ExpressionNode> m_subscript;
+ };
+
+ class DotAccessorNode : public ExpressionNode {
+ public:
+ DotAccessorNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
+ : m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecMember; }
+
+ virtual bool isLocation() const KJS_FAST_CALL { return true; }
+ virtual bool isDotAccessorNode() const KJS_FAST_CALL { return true; }
+ ExpressionNode* base() const KJS_FAST_CALL { return m_base.get(); }
+ const Identifier& identifier() const KJS_FAST_CALL { return m_ident; }
+
+ private:
+ ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
+
+ RefPtr<ExpressionNode> m_base;
+ Identifier m_ident;
+ };
+
+ class ArgumentListNode : public Node {
+ public:
+ ArgumentListNode(ExpressionNode* expr) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ }
+
+ ArgumentListNode(ArgumentListNode* listNode, ExpressionNode* expr) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ listNode->m_next = this;
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+
+ void evaluateList(ExecState*, List&) KJS_FAST_CALL;
+ PassRefPtr<ArgumentListNode> releaseNext() KJS_FAST_CALL { return m_next.release(); }
+
+ private:
+ friend class ArgumentsNode;
+ ListRefPtr<ArgumentListNode> m_next;
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class ArgumentsNode : public Node {
+ public:
+ ArgumentsNode() KJS_FAST_CALL
+ {
+ }
+
+ ArgumentsNode(ArgumentListNode* listNode) KJS_FAST_CALL
+ : m_listNode(listNode)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+
+ void evaluateList(ExecState* exec, List& list) KJS_FAST_CALL { if (m_listNode) m_listNode->evaluateList(exec, list); }
+
+ private:
+ RefPtr<ArgumentListNode> m_listNode;
+ };
+
+ class NewExprNode : public ExpressionNode {
+ public:
+ NewExprNode(ExpressionNode* expr) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ }
+
+ NewExprNode(ExpressionNode* expr, ArgumentsNode* args) KJS_FAST_CALL
+ : m_expr(expr)
+ , m_args(args)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecLeftHandSide; }
+
+ private:
+ ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr;
+ RefPtr<ArgumentsNode> m_args;
+ };
+
+ class FunctionCallValueNode : public ExpressionNode {
+ public:
+ FunctionCallValueNode(ExpressionNode* expr, ArgumentsNode* args) KJS_FAST_CALL
+ : m_expr(expr)
+ , m_args(args)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecCall; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ RefPtr<ArgumentsNode> m_args;
+ };
+
+ class FunctionCallResolveNode : public ExpressionNode {
+ public:
+ FunctionCallResolveNode(const Identifier& ident, ArgumentsNode* args) KJS_FAST_CALL
+ : m_ident(ident)
+ , m_args(args)
+ {
+ }
+
+ FunctionCallResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : ExpressionNode(PlacementNewAdopt)
+ , m_ident(PlacementNewAdopt)
+ , m_args(PlacementNewAdopt)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecCall; }
+
+ protected:
+ ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
+
+ Identifier m_ident;
+ RefPtr<ArgumentsNode> m_args;
+ size_t m_index; // Used by LocalVarFunctionCallNode.
+ };
+
+ class LocalVarFunctionCallNode : public FunctionCallResolveNode {
+ public:
+ LocalVarFunctionCallNode(size_t i) KJS_FAST_CALL
+ : FunctionCallResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+
+ private:
+ ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
+ };
+
+ class FunctionCallBracketNode : public ExpressionNode {
+ public:
+ FunctionCallBracketNode(ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args) KJS_FAST_CALL
+ : m_base(base)
+ , m_subscript(subscript)
+ , m_args(args)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecCall; }
+
+ protected:
+ RefPtr<ExpressionNode> m_base;
+ RefPtr<ExpressionNode> m_subscript;
+ RefPtr<ArgumentsNode> m_args;
+ };
+
+ class FunctionCallDotNode : public ExpressionNode {
+ public:
+ FunctionCallDotNode(ExpressionNode* base, const Identifier& ident, ArgumentsNode* args) KJS_FAST_CALL
+ : m_base(base)
+ , m_ident(ident)
+ , m_args(args)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecCall; }
+
+ private:
+ ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
+
+ RefPtr<ExpressionNode> m_base;
+ Identifier m_ident;
+ RefPtr<ArgumentsNode> m_args;
+ };
+
+ class PrePostResolveNode : public ExpressionNode {
+ public:
+ PrePostResolveNode(const Identifier& ident) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_ident(ident)
+ {
+ }
+
+ PrePostResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : ExpressionNode(PlacementNewAdopt)
+ , m_ident(PlacementNewAdopt)
+ {
+ }
+
+ protected:
+ Identifier m_ident;
+ size_t m_index; // Used by LocalVarPostfixNode.
+ };
+
+ class PostIncResolveNode : public PrePostResolveNode {
+ public:
+ PostIncResolveNode(const Identifier& ident) KJS_FAST_CALL
+ : PrePostResolveNode(ident)
+ {
+ }
+
+ PostIncResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : PrePostResolveNode(PlacementNewAdopt)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPostfix; }
+ virtual void optimizeForUnnecessaryResult();
+ };
+
+ class PostIncLocalVarNode : public PostIncResolveNode {
+ public:
+ PostIncLocalVarNode(size_t i) KJS_FAST_CALL
+ : PostIncResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void optimizeForUnnecessaryResult();
+ };
+
+ class PostIncConstNode : public PostIncResolveNode {
+ public:
+ PostIncConstNode(size_t i) KJS_FAST_CALL
+ : PostIncResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class PostDecResolveNode : public PrePostResolveNode {
+ public:
+ PostDecResolveNode(const Identifier& ident) KJS_FAST_CALL
+ : PrePostResolveNode(ident)
+ {
+ }
+
+ PostDecResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : PrePostResolveNode(PlacementNewAdopt)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPostfix; }
+ virtual void optimizeForUnnecessaryResult();
+ };
+
+ class PostDecLocalVarNode : public PostDecResolveNode {
+ public:
+ PostDecLocalVarNode(size_t i) KJS_FAST_CALL
+ : PostDecResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void optimizeForUnnecessaryResult();
+
+ private:
+ ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
+ };
+
+ class PostDecConstNode : public PostDecResolveNode {
+ public:
+ PostDecConstNode(size_t i) KJS_FAST_CALL
+ : PostDecResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class PostfixBracketNode : public ExpressionNode {
+ public:
+ PostfixBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
+ : m_base(base)
+ , m_subscript(subscript)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPostfix; }
+
+ protected:
+ RefPtr<ExpressionNode> m_base;
+ RefPtr<ExpressionNode> m_subscript;
+ };
+
+ class PostIncBracketNode : public PostfixBracketNode {
+ public:
+ PostIncBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
+ : PostfixBracketNode(base, subscript)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ };
+
+ class PostDecBracketNode : public PostfixBracketNode {
+ public:
+ PostDecBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
+ : PostfixBracketNode(base, subscript)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ };
+
+ class PostfixDotNode : public ExpressionNode {
+ public:
+ PostfixDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
+ : m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPostfix; }
+
+ protected:
+ RefPtr<ExpressionNode> m_base;
+ Identifier m_ident;
+ };
+
+ class PostIncDotNode : public PostfixDotNode {
+ public:
+ PostIncDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
+ : PostfixDotNode(base, ident)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ };
+
+ class PostDecDotNode : public PostfixDotNode {
+ public:
+ PostDecDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
+ : PostfixDotNode(base, ident)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ };
+
+ class PostfixErrorNode : public ExpressionNode {
+ public:
+ PostfixErrorNode(ExpressionNode* expr, Operator oper) KJS_FAST_CALL
+ : m_expr(expr)
+ , m_operator(oper)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPostfix; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ Operator m_operator;
+ };
+
+ class DeleteResolveNode : public ExpressionNode {
+ public:
+ DeleteResolveNode(const Identifier& ident) KJS_FAST_CALL
+ : m_ident(ident)
+ {
+ }
+
+ DeleteResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : ExpressionNode(PlacementNewAdopt)
+ , m_ident(PlacementNewAdopt)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ Identifier m_ident;
+ };
+
+ class LocalVarDeleteNode : public DeleteResolveNode {
+ public:
+ LocalVarDeleteNode() KJS_FAST_CALL
+ : DeleteResolveNode(PlacementNewAdopt)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class DeleteBracketNode : public ExpressionNode {
+ public:
+ DeleteBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
+ : m_base(base)
+ , m_subscript(subscript)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ RefPtr<ExpressionNode> m_base;
+ RefPtr<ExpressionNode> m_subscript;
+ };
+
+ class DeleteDotNode : public ExpressionNode {
+ public:
+ DeleteDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
+ : m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ RefPtr<ExpressionNode> m_base;
+ Identifier m_ident;
+ };
+
+ class DeleteValueNode : public ExpressionNode {
+ public:
+ DeleteValueNode(ExpressionNode* expr) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class VoidNode : public ExpressionNode {
+ public:
+ VoidNode(ExpressionNode* expr) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class TypeOfResolveNode : public ExpressionNode {
+ public:
+ TypeOfResolveNode(const Identifier& ident) KJS_FAST_CALL
+ : ExpressionNode(StringType)
+ , m_ident(ident)
+ {
+ }
+
+ TypeOfResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : ExpressionNode(PlacementNewAdopt)
+ , m_ident(PlacementNewAdopt)
+ {
+ m_expectedReturnType = StringType;
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ const Identifier& identifier() const KJS_FAST_CALL { return m_ident; }
+
+ protected:
+ Identifier m_ident;
+ size_t m_index; // Used by LocalTypeOfNode.
+ };
+
+ class LocalVarTypeOfNode : public TypeOfResolveNode {
+ public:
+ LocalVarTypeOfNode(size_t i) KJS_FAST_CALL
+ : TypeOfResolveNode(PlacementNewAdopt)
+ {
+ m_expectedReturnType = StringType;
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class TypeOfValueNode : public ExpressionNode {
+ public:
+ TypeOfValueNode(ExpressionNode* expr) KJS_FAST_CALL
+ : ExpressionNode(StringType)
+ , m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class PreIncResolveNode : public PrePostResolveNode {
+ public:
+ PreIncResolveNode(const Identifier& ident) KJS_FAST_CALL
+ : PrePostResolveNode(ident)
+ {
+ }
+
+ PreIncResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : PrePostResolveNode(PlacementNewAdopt)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+ };
+
+ class PreIncLocalVarNode : public PreIncResolveNode {
+ public:
+ PreIncLocalVarNode(size_t i) KJS_FAST_CALL
+ : PreIncResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class PreIncConstNode : public PreIncResolveNode {
+ public:
+ PreIncConstNode(size_t i) KJS_FAST_CALL
+ : PreIncResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class PreDecResolveNode : public PrePostResolveNode {
+ public:
+ PreDecResolveNode(const Identifier& ident) KJS_FAST_CALL
+ : PrePostResolveNode(ident)
+ {
+ }
+
+ PreDecResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : PrePostResolveNode(PlacementNewAdopt)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+ };
+
+ class PreDecLocalVarNode : public PreDecResolveNode {
+ public:
+ PreDecLocalVarNode(size_t i) KJS_FAST_CALL
+ : PreDecResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class PreDecConstNode : public PreDecResolveNode {
+ public:
+ PreDecConstNode(size_t i) KJS_FAST_CALL
+ : PreDecResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class PrefixBracketNode : public ExpressionNode {
+ public:
+ PrefixBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
+ : m_base(base)
+ , m_subscript(subscript)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ protected:
+ RefPtr<ExpressionNode> m_base;
+ RefPtr<ExpressionNode> m_subscript;
+ };
+
+ class PreIncBracketNode : public PrefixBracketNode {
+ public:
+ PreIncBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
+ : PrefixBracketNode(base, subscript)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ };
+
+ class PreDecBracketNode : public PrefixBracketNode {
+ public:
+ PreDecBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
+ : PrefixBracketNode(base, subscript)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ };
+
+ class PrefixDotNode : public ExpressionNode {
+ public:
+ PrefixDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
+ : m_base(base)
+ , m_ident(ident)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPostfix; }
+
+ protected:
+ RefPtr<ExpressionNode> m_base;
+ Identifier m_ident;
+ };
+
+ class PreIncDotNode : public PrefixDotNode {
+ public:
+ PreIncDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
+ : PrefixDotNode(base, ident)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ };
+
+ class PreDecDotNode : public PrefixDotNode {
+ public:
+ PreDecDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
+ : PrefixDotNode(base, ident)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ };
+
+ class PrefixErrorNode : public ExpressionNode {
+ public:
+ PrefixErrorNode(ExpressionNode* expr, Operator oper) KJS_FAST_CALL
+ : m_expr(expr)
+ , m_operator(oper)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ Operator m_operator;
+ };
+
+ class UnaryPlusNode : public ExpressionNode {
+ public:
+ UnaryPlusNode(ExpressionNode* expr) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class NegateNode : public ExpressionNode {
+ public:
+ NegateNode(ExpressionNode* expr) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class BitwiseNotNode : public ExpressionNode {
+ public:
+ BitwiseNotNode(ExpressionNode* expr) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ ALWAYS_INLINE int32_t inlineEvaluateToInt32(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class LogicalNotNode : public ExpressionNode {
+ public:
+ LogicalNotNode(ExpressionNode* expr) KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ , m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class MultNode : public ExpressionNode {
+ public:
+ MultNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_term1(term1)
+ , m_term2(term2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecMultiplicitave; }
+
+ private:
+ ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
+
+ RefPtr<ExpressionNode> m_term1;
+ RefPtr<ExpressionNode> m_term2;
+ };
+
+ class DivNode : public ExpressionNode {
+ public:
+ DivNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_term1(term1)
+ , m_term2(term2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecMultiplicitave; }
+
+ private:
+ ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
+
+ RefPtr<ExpressionNode> m_term1;
+ RefPtr<ExpressionNode> m_term2;
+ };
+
+ class ModNode : public ExpressionNode {
+ public:
+ ModNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_term1(term1)
+ , m_term2(term2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecMultiplicitave; }
+
+ private:
+ ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
+
+ RefPtr<ExpressionNode> m_term1;
+ RefPtr<ExpressionNode> m_term2;
+ };
+
+ class AddNode : public ExpressionNode {
+ public:
+ AddNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : m_term1(term1)
+ , m_term2(term2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAdditive; }
+
+ protected:
+ AddNode(ExpressionNode* term1, ExpressionNode* term2, JSType expectedReturn) KJS_FAST_CALL
+ : ExpressionNode(expectedReturn)
+ , m_term1(term1)
+ , m_term2(term2)
+ {
+ }
+
+ RefPtr<ExpressionNode> m_term1;
+ RefPtr<ExpressionNode> m_term2;
+
+ private:
+ ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
+ };
+
+ class AddNumbersNode : public AddNode {
+ public:
+ AddNumbersNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : AddNode(term1, term2, NumberType)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+
+ private:
+ ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*) KJS_FAST_CALL;
+ };
+
+ class AddStringLeftNode : public AddNode {
+ public:
+ AddStringLeftNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : AddNode(term1, term2, StringType)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class AddStringRightNode : public AddNode {
+ public:
+ AddStringRightNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : AddNode(term1, term2, StringType)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class AddStringsNode : public AddNode {
+ public:
+ AddStringsNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : AddNode(term1, term2, StringType)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class SubNode : public ExpressionNode {
+ public:
+ SubNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_term1(term1)
+ , m_term2(term2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAdditive; }
+
+ private:
+ ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
+
+ RefPtr<ExpressionNode> m_term1;
+ RefPtr<ExpressionNode> m_term2;
+ };
+
+ class LeftShiftNode : public ExpressionNode {
+ public:
+ LeftShiftNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_term1(term1)
+ , m_term2(term2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecShift; }
+
+ private:
+ ALWAYS_INLINE int32_t inlineEvaluateToInt32(ExecState*);
+
+ RefPtr<ExpressionNode> m_term1;
+ RefPtr<ExpressionNode> m_term2;
+ };
+
+ class RightShiftNode : public ExpressionNode {
+ public:
+ RightShiftNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_term1(term1)
+ , m_term2(term2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecShift; }
+
+ private:
+ ALWAYS_INLINE int32_t inlineEvaluateToInt32(ExecState*);
+
+ RefPtr<ExpressionNode> m_term1;
+ RefPtr<ExpressionNode> m_term2;
+ };
+
+ class UnsignedRightShiftNode : public ExpressionNode {
+ public:
+ UnsignedRightShiftNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_term1(term1)
+ , m_term2(term2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecShift; }
+ private:
+ ALWAYS_INLINE uint32_t inlineEvaluateToUInt32(ExecState*);
+
+ RefPtr<ExpressionNode> m_term1;
+ RefPtr<ExpressionNode> m_term2;
+ };
+
+ class LessNode : public ExpressionNode {
+ public:
+ LessNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecRelational; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ protected:
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class LessNumbersNode : public LessNode {
+ public:
+ LessNumbersNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : LessNode(expr1, expr2)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+ };
+
+ class LessStringsNode : public LessNode {
+ public:
+ LessStringsNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : LessNode(expr1, expr2)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+ };
+
+ class GreaterNode : public ExpressionNode {
+ public:
+ GreaterNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecRelational; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class LessEqNode : public ExpressionNode {
+ public:
+ LessEqNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecRelational; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class GreaterEqNode : public ExpressionNode {
+ public:
+ GreaterEqNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecRelational; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class InstanceOfNode : public ExpressionNode {
+ public:
+ InstanceOfNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecRelational; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class InNode : public ExpressionNode {
+ public:
+ InNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecRelational; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class EqualNode : public ExpressionNode {
+ public:
+ EqualNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecEquality; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class NotEqualNode : public ExpressionNode {
+ public:
+ NotEqualNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecEquality; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class StrictEqualNode : public ExpressionNode {
+ public:
+ StrictEqualNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecEquality; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class NotStrictEqualNode : public ExpressionNode {
+ public:
+ NotStrictEqualNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecEquality; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class BitAndNode : public ExpressionNode {
+ public:
+ BitAndNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecBitwiseAnd; }
+
+ private:
+ ALWAYS_INLINE int32_t inlineEvaluateToInt32(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class BitOrNode : public ExpressionNode {
+ public:
+ BitOrNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecBitwiseOr; }
+
+ private:
+ ALWAYS_INLINE int32_t inlineEvaluateToInt32(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class BitXOrNode : public ExpressionNode {
+ public:
+ BitXOrNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(NumberType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecBitwiseXor; }
+
+ private:
+ ALWAYS_INLINE int32_t inlineEvaluateToInt32(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ /**
+ * m_expr1 && m_expr2, m_expr1 || m_expr2
+ */
+ class LogicalAndNode : public ExpressionNode {
+ public:
+ LogicalAndNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecLogicalAnd; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class LogicalOrNode : public ExpressionNode {
+ public:
+ LogicalOrNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : ExpressionNode(BooleanType)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecLogicalOr; }
+
+ private:
+ ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ /**
+ * The ternary operator, "m_logical ? m_expr1 : m_expr2"
+ */
+ class ConditionalNode : public ExpressionNode {
+ public:
+ ConditionalNode(ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : m_logical(logical)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
+ virtual double evaluateToNumber(ExecState*) KJS_FAST_CALL;
+ virtual int32_t evaluateToInt32(ExecState*) KJS_FAST_CALL;
+ virtual uint32_t evaluateToUInt32(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecConditional; }
+
+ private:
+ RefPtr<ExpressionNode> m_logical;
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class ReadModifyResolveNode : public ExpressionNode {
+ public:
+ ReadModifyResolveNode(const Identifier& ident, Operator oper, ExpressionNode* right) KJS_FAST_CALL
+ : m_ident(ident)
+ , m_operator(oper)
+ , m_right(right)
+ {
+ }
+
+ ReadModifyResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : ExpressionNode(PlacementNewAdopt)
+ , m_ident(PlacementNewAdopt)
+ , m_right(PlacementNewAdopt)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAssignment; }
+
+ protected:
+ Identifier m_ident;
+ Operator m_operator;
+ RefPtr<ExpressionNode> m_right;
+ size_t m_index; // Used by ReadModifyLocalVarNode.
+ };
+
+ class ReadModifyLocalVarNode : public ReadModifyResolveNode {
+ public:
+ ReadModifyLocalVarNode(size_t i) KJS_FAST_CALL
+ : ReadModifyResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class ReadModifyConstNode : public ReadModifyResolveNode {
+ public:
+ ReadModifyConstNode(size_t i) KJS_FAST_CALL
+ : ReadModifyResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class AssignResolveNode : public ExpressionNode {
+ public:
+ AssignResolveNode(const Identifier& ident, ExpressionNode* right) KJS_FAST_CALL
+ : m_ident(ident)
+ , m_right(right)
+ {
+ }
+
+ AssignResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
+ : ExpressionNode(PlacementNewAdopt)
+ , m_ident(PlacementNewAdopt)
+ , m_right(PlacementNewAdopt)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAssignment; }
+
+ protected:
+ Identifier m_ident;
+ RefPtr<ExpressionNode> m_right;
+ size_t m_index; // Used by ReadModifyLocalVarNode.
+ };
+
+ class AssignLocalVarNode : public AssignResolveNode {
+ public:
+ AssignLocalVarNode(size_t i) KJS_FAST_CALL
+ : AssignResolveNode(PlacementNewAdopt)
+ {
+ ASSERT(i != missingSymbolMarker());
+ m_index = i;
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class AssignConstNode : public AssignResolveNode {
+ public:
+ AssignConstNode() KJS_FAST_CALL
+ : AssignResolveNode(PlacementNewAdopt)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ };
+
+ class ReadModifyBracketNode : public ExpressionNode {
+ public:
+ ReadModifyBracketNode(ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right) KJS_FAST_CALL
+ : m_base(base)
+ , m_subscript(subscript)
+ , m_operator(oper)
+ , m_right(right)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAssignment; }
+
+ protected:
+ RefPtr<ExpressionNode> m_base;
+ RefPtr<ExpressionNode> m_subscript;
+ Operator m_operator;
+ RefPtr<ExpressionNode> m_right;
+ };
+
+ class AssignBracketNode : public ExpressionNode {
+ public:
+ AssignBracketNode(ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right) KJS_FAST_CALL
+ : m_base(base)
+ , m_subscript(subscript)
+ , m_right(right)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAssignment; }
+
+ protected:
+ RefPtr<ExpressionNode> m_base;
+ RefPtr<ExpressionNode> m_subscript;
+ RefPtr<ExpressionNode> m_right;
+ };
+
+ class AssignDotNode : public ExpressionNode {
+ public:
+ AssignDotNode(ExpressionNode* base, const Identifier& ident, ExpressionNode* right) KJS_FAST_CALL
+ : m_base(base)
+ , m_ident(ident)
+ , m_right(right)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAssignment; }
+
+ protected:
+ RefPtr<ExpressionNode> m_base;
+ Identifier m_ident;
+ RefPtr<ExpressionNode> m_right;
+ };
+
+ class ReadModifyDotNode : public ExpressionNode {
+ public:
+ ReadModifyDotNode(ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right) KJS_FAST_CALL
+ : m_base(base)
+ , m_ident(ident)
+ , m_operator(oper)
+ , m_right(right)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAssignment; }
+
+ protected:
+ RefPtr<ExpressionNode> m_base;
+ Identifier m_ident;
+ Operator m_operator;
+ RefPtr<ExpressionNode> m_right;
+ };
+
+ class AssignErrorNode : public ExpressionNode {
+ public:
+ AssignErrorNode(ExpressionNode* left, Operator oper, ExpressionNode* right) KJS_FAST_CALL
+ : m_left(left)
+ , m_operator(oper)
+ , m_right(right)
+ {
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAssignment; }
+
+ protected:
+ RefPtr<ExpressionNode> m_left;
+ Operator m_operator;
+ RefPtr<ExpressionNode> m_right;
+ };
+
+ class CommaNode : public ExpressionNode {
+ public:
+ CommaNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : m_expr1(expr1)
+ , m_expr2(expr2)
+ {
+ m_expr1->optimizeForUnnecessaryResult();
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecExpression; }
+
+ private:
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ };
+
+ class VarDeclCommaNode : public CommaNode {
+ public:
+ VarDeclCommaNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
+ : CommaNode(expr1, expr2)
+ {
+ }
+ virtual Precedence precedence() const { return PrecAssignment; }
+ };
+
+ class ConstDeclNode : public ExpressionNode {
+ public:
+ ConstDeclNode(const Identifier& ident, ExpressionNode* in) KJS_FAST_CALL;
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual KJS::JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ void evaluateSingle(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+ PassRefPtr<ConstDeclNode> releaseNext() KJS_FAST_CALL { return m_next.release(); }
+
+ Identifier m_ident;
+ ListRefPtr<ConstDeclNode> m_next;
+ RefPtr<ExpressionNode> m_init;
+
+ private:
+ void handleSlowCase(ExecState*, const ScopeChain&, JSValue*) KJS_FAST_CALL NEVER_INLINE;
+ };
+
+ class ConstStatementNode : public StatementNode {
+ public:
+ ConstStatementNode(ConstDeclNode* next) KJS_FAST_CALL
+ : m_next(next)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<ConstDeclNode> m_next;
+ };
+
+ typedef Vector<RefPtr<StatementNode> > StatementVector;
+
+ class SourceElements : public ParserRefCounted {
+ public:
+ void append(PassRefPtr<StatementNode>);
+ void releaseContentsIntoVector(StatementVector& destination)
+ {
+ ASSERT(destination.isEmpty());
+ m_statements.swap(destination);
+ }
+
+ private:
+ StatementVector m_statements;
+ };
+
+ class BlockNode : public StatementNode {
+ public:
+ BlockNode(SourceElements* children) KJS_FAST_CALL;
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ protected:
+ StatementVector m_children;
+ };
+
+ class EmptyStatementNode : public StatementNode {
+ public:
+ EmptyStatementNode() KJS_FAST_CALL // debug
+ {
+ }
+
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual bool isEmptyStatement() const KJS_FAST_CALL { return true; }
+ };
+
+ class ExprStatementNode : public StatementNode {
+ public:
+ ExprStatementNode(ExpressionNode* expr) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class VarStatementNode : public StatementNode {
+ public:
+ VarStatementNode(ExpressionNode* expr) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class IfNode : public StatementNode {
+ public:
+ IfNode(ExpressionNode* condition, StatementNode* ifBlock) KJS_FAST_CALL
+ : m_condition(condition)
+ , m_ifBlock(ifBlock)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ protected:
+ RefPtr<ExpressionNode> m_condition;
+ RefPtr<StatementNode> m_ifBlock;
+ };
+
+ class IfElseNode : public IfNode {
+ public:
+ IfElseNode(ExpressionNode* condtion, StatementNode* ifBlock, StatementNode* elseBlock) KJS_FAST_CALL
+ : IfNode(condtion, ifBlock)
+ , m_elseBlock(elseBlock)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<StatementNode> m_elseBlock;
+ };
+
+ class DoWhileNode : public StatementNode {
+ public:
+ DoWhileNode(StatementNode* statement, ExpressionNode* expr) KJS_FAST_CALL
+ : m_statement(statement)
+ , m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<StatementNode> m_statement;
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class WhileNode : public StatementNode {
+ public:
+ WhileNode(ExpressionNode* expr, StatementNode* statement) KJS_FAST_CALL
+ : m_expr(expr)
+ , m_statement(statement)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ RefPtr<StatementNode> m_statement;
+ };
+
+ class ForNode : public StatementNode {
+ public:
+ ForNode(ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, bool expr1WasVarDecl) KJS_FAST_CALL
+ : m_expr1(expr1 ? expr1 : new PlaceholderTrueNode)
+ , m_expr2(expr2 ? expr2 : new PlaceholderTrueNode)
+ , m_expr3(expr3 ? expr3 : new PlaceholderTrueNode)
+ , m_statement(statement)
+ , m_expr1WasVarDecl(expr1 && expr1WasVarDecl)
+ {
+ ASSERT(m_expr1);
+ ASSERT(m_expr2);
+ ASSERT(m_expr3);
+ ASSERT(statement);
+
+ m_expr1->optimizeForUnnecessaryResult();
+ m_expr3->optimizeForUnnecessaryResult();
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ RefPtr<ExpressionNode> m_expr3;
+ RefPtr<StatementNode> m_statement;
+ bool m_expr1WasVarDecl;
+ };
+
+ class ForInNode : public StatementNode {
+ public:
+ ForInNode(ExpressionNode*, ExpressionNode*, StatementNode*) KJS_FAST_CALL;
+ ForInNode(const Identifier&, ExpressionNode*, ExpressionNode*, StatementNode*) KJS_FAST_CALL;
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ Identifier m_ident;
+ RefPtr<ExpressionNode> m_init;
+ RefPtr<ExpressionNode> m_lexpr;
+ RefPtr<ExpressionNode> m_expr;
+ RefPtr<StatementNode> m_statement;
+ bool m_identIsVarDecl;
+ };
+
+ class ContinueNode : public StatementNode {
+ public:
+ ContinueNode() KJS_FAST_CALL
+ {
+ }
+
+ ContinueNode(const Identifier& ident) KJS_FAST_CALL
+ : m_ident(ident)
+ {
+ }
+
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ Identifier m_ident;
+ };
+
+ class BreakNode : public StatementNode {
+ public:
+ BreakNode() KJS_FAST_CALL
+ {
+ }
+
+ BreakNode(const Identifier& ident) KJS_FAST_CALL
+ : m_ident(ident)
+ {
+ }
+
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ Identifier m_ident;
+ };
+
+ class ReturnNode : public StatementNode {
+ public:
+ ReturnNode(ExpressionNode* value) KJS_FAST_CALL
+ : m_value(value)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<ExpressionNode> m_value;
+ };
+
+ class WithNode : public StatementNode {
+ public:
+ WithNode(ExpressionNode* expr, StatementNode* statement) KJS_FAST_CALL
+ : m_expr(expr)
+ , m_statement(statement)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ RefPtr<StatementNode> m_statement;
+ };
+
+ class LabelNode : public StatementNode {
+ public:
+ LabelNode(const Identifier& label, StatementNode* statement) KJS_FAST_CALL
+ : m_label(label)
+ , m_statement(statement)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual void pushLabel(const Identifier& ident) KJS_FAST_CALL { m_statement->pushLabel(ident); }
+
+ private:
+ Identifier m_label;
+ RefPtr<StatementNode> m_statement;
+ };
+
+ class ThrowNode : public StatementNode {
+ public:
+ ThrowNode(ExpressionNode* expr) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ };
+
+ class TryNode : public StatementNode {
+ public:
+ TryNode(StatementNode* tryBlock, const Identifier& exceptionIdent, StatementNode* catchBlock, StatementNode* finallyBlock) KJS_FAST_CALL
+ : m_tryBlock(tryBlock)
+ , m_exceptionIdent(exceptionIdent)
+ , m_catchBlock(catchBlock)
+ , m_finallyBlock(finallyBlock)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<StatementNode> m_tryBlock;
+ Identifier m_exceptionIdent;
+ RefPtr<StatementNode> m_catchBlock;
+ RefPtr<StatementNode> m_finallyBlock;
+ };
+
+ class ParameterNode : public Node {
+ public:
+ ParameterNode(const Identifier& ident) KJS_FAST_CALL
+ : m_ident(ident)
+ {
+ }
+
+ ParameterNode(ParameterNode* l, const Identifier& ident) KJS_FAST_CALL
+ : m_ident(ident)
+ {
+ l->m_next = this;
+ }
+
+ Identifier ident() KJS_FAST_CALL { return m_ident; }
+ ParameterNode *nextParam() KJS_FAST_CALL { return m_next.get(); }
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ PassRefPtr<ParameterNode> releaseNext() KJS_FAST_CALL { return m_next.release(); }
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+
+ private:
+ friend class FuncDeclNode;
+ friend class FuncExprNode;
+ Identifier m_ident;
+ ListRefPtr<ParameterNode> m_next;
+ };
+
+ class ScopeNode : public BlockNode {
+ public:
+ ScopeNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+
+ int sourceId() const KJS_FAST_CALL { return m_sourceId; }
+ const UString& sourceURL() const KJS_FAST_CALL { return m_sourceURL; }
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ protected:
+ void optimizeVariableAccess(ExecState*) KJS_FAST_CALL;
+
+ VarStack m_varStack;
+ FunctionStack m_functionStack;
+
+ private:
+ UString m_sourceURL;
+ int m_sourceId;
+ };
+
+ class ProgramNode : public ScopeNode {
+ public:
+ static ProgramNode* create(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+
+ private:
+ ProgramNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+
+ void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
+ ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+
+ Vector<size_t> m_varIndexes; // Storage indexes belonging to the nodes in m_varStack. (Recorded to avoid double lookup.)
+ Vector<size_t> m_functionIndexes; // Storage indexes belonging to the nodes in m_functionStack. (Recorded to avoid double lookup.)
+ };
+
+ class EvalNode : public ScopeNode {
+ public:
+ static EvalNode* create(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+
+ private:
+ EvalNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+
+ ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+ };
+
+ class FunctionBodyNode : public ScopeNode {
+ public:
+ static FunctionBodyNode* create(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+
+ SymbolTable& symbolTable() KJS_FAST_CALL { return m_symbolTable; }
+
+ Vector<Identifier>& parameters() KJS_FAST_CALL { return m_parameters; }
+ UString paramString() const KJS_FAST_CALL;
+
+ protected:
+ FunctionBodyNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+
+ private:
+ void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
+ ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+
+ bool m_initialized;
+ Vector<Identifier> m_parameters;
+ SymbolTable m_symbolTable;
+ };
+
+ class FuncExprNode : public ExpressionNode {
+ public:
+ FuncExprNode(const Identifier& ident, FunctionBodyNode* body, ParameterNode* parameter = 0) KJS_FAST_CALL
+ : m_ident(ident)
+ , m_parameter(parameter)
+ , m_body(body)
+ {
+ addParams();
+ }
+
+ virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { return PrecMember; }
+ virtual bool needsParensIfLeftmost() const { return true; }
+
+ private:
+ void addParams() KJS_FAST_CALL;
+
+ // Used for streamTo
+ friend class PropertyNode;
+ Identifier m_ident;
+ RefPtr<ParameterNode> m_parameter;
+ RefPtr<FunctionBodyNode> m_body;
+ };
+
+ class FuncDeclNode : public StatementNode {
+ public:
+ FuncDeclNode(const Identifier& ident, FunctionBodyNode* body) KJS_FAST_CALL
+ : m_ident(ident)
+ , m_body(body)
+ {
+ addParams();
+ }
+
+ FuncDeclNode(const Identifier& ident, ParameterNode* parameter, FunctionBodyNode* body) KJS_FAST_CALL
+ : m_ident(ident)
+ , m_parameter(parameter)
+ , m_body(body)
+ {
+ addParams();
+ }
+
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ ALWAYS_INLINE FunctionImp* makeFunction(ExecState*) KJS_FAST_CALL;
+
+ Identifier m_ident;
+
+ private:
+ void addParams() KJS_FAST_CALL;
+
+ RefPtr<ParameterNode> m_parameter;
+ RefPtr<FunctionBodyNode> m_body;
+ };
+
+ class CaseClauseNode : public Node {
+ public:
+ CaseClauseNode(ExpressionNode* expr) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ }
+
+ CaseClauseNode(ExpressionNode* expr, SourceElements* children) KJS_FAST_CALL
+ : m_expr(expr)
+ {
+ if (children)
+ children->releaseContentsIntoVector(m_children);
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+
+ JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ JSValue* executeStatements(ExecState*) KJS_FAST_CALL;
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ StatementVector m_children;
+ };
+
+ class ClauseListNode : public Node {
+ public:
+ ClauseListNode(CaseClauseNode* clause) KJS_FAST_CALL
+ : m_clause(clause)
+ {
+ }
+
+ ClauseListNode(ClauseListNode* clauseList, CaseClauseNode* clause) KJS_FAST_CALL
+ : m_clause(clause)
+ {
+ clauseList->m_next = this;
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ CaseClauseNode* getClause() const KJS_FAST_CALL { return m_clause.get(); }
+ ClauseListNode* getNext() const KJS_FAST_CALL { return m_next.get(); }
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ PassRefPtr<ClauseListNode> releaseNext() KJS_FAST_CALL { return m_next.release(); }
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+
+ private:
+ friend class CaseBlockNode;
+ RefPtr<CaseClauseNode> m_clause;
+ ListRefPtr<ClauseListNode> m_next;
+ };
+
+ class CaseBlockNode : public Node {
+ public:
+ CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2) KJS_FAST_CALL;
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ JSValue* executeBlock(ExecState*, JSValue *input) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
+
+ private:
+ RefPtr<ClauseListNode> m_list1;
+ RefPtr<CaseClauseNode> m_defaultClause;
+ RefPtr<ClauseListNode> m_list2;
+ };
+
+ class SwitchNode : public StatementNode {
+ public:
+ SwitchNode(ExpressionNode* expr, CaseBlockNode* block) KJS_FAST_CALL
+ : m_expr(expr)
+ , m_block(block)
+ {
+ }
+
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ private:
+ RefPtr<ExpressionNode> m_expr;
+ RefPtr<CaseBlockNode> m_block;
+ };
+
+ class BreakpointCheckStatement : public StatementNode {
+ public:
+ BreakpointCheckStatement(PassRefPtr<StatementNode>) KJS_FAST_CALL;
+
+ virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+
+ private:
+ RefPtr<StatementNode> m_statement;
+ };
+
+ struct ElementList {
+ ElementNode* head;
+ ElementNode* tail;
+ };
+
+ struct PropertyList {
+ PropertyListNode* head;
+ PropertyListNode* tail;
+ };
+
+ struct ArgumentList {
+ ArgumentListNode* head;
+ ArgumentListNode* tail;
+ };
+
+ struct ConstDeclList {
+ ConstDeclNode* head;
+ ConstDeclNode* tail;
+ };
+
+ struct ParameterList {
+ ParameterNode* head;
+ ParameterNode* tail;
+ };
+
+ struct ClauseList {
+ ClauseListNode* head;
+ ClauseListNode* tail;
+ };
+
+} // namespace KJS
+
+#endif // NODES_H_
diff --git a/JavaScriptCore/kjs/nodes2string.cpp b/JavaScriptCore/kjs/nodes2string.cpp
new file mode 100644
index 0000000..b10e180
--- /dev/null
+++ b/JavaScriptCore/kjs/nodes2string.cpp
@@ -0,0 +1,973 @@
+/*
+ * Copyright (C) 2002 Harri Porten (porten@kde.org)
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Eric Seidel <eric@webkit.org>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU 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 "nodes.h"
+
+#include <wtf/MathExtras.h>
+#include <wtf/StringExtras.h>
+#include <wtf/unicode/Unicode.h>
+
+using namespace WTF;
+using namespace Unicode;
+
+namespace KJS {
+
+// A simple text streaming class that helps with code indentation.
+
+enum EndlType { Endl };
+enum IndentType { Indent };
+enum UnindentType { Unindent };
+enum DotExprType { DotExpr };
+
+class SourceStream {
+public:
+ SourceStream()
+ : m_numberNeedsParens(false)
+ , m_atStartOfStatement(true)
+ , m_precedence(PrecExpression)
+ {
+ }
+
+ UString toString() const { return m_string; }
+
+ SourceStream& operator<<(const Identifier&);
+ SourceStream& operator<<(const UString&);
+ SourceStream& operator<<(const char*);
+ SourceStream& operator<<(double);
+ SourceStream& operator<<(char);
+ SourceStream& operator<<(EndlType);
+ SourceStream& operator<<(IndentType);
+ SourceStream& operator<<(UnindentType);
+ SourceStream& operator<<(DotExprType);
+ SourceStream& operator<<(Precedence);
+ SourceStream& operator<<(const Node*);
+ template <typename T> SourceStream& operator<<(const RefPtr<T>& n) { return *this << n.get(); }
+
+private:
+ UString m_string;
+ UString m_spacesForIndentation;
+ bool m_numberNeedsParens;
+ bool m_atStartOfStatement;
+ Precedence m_precedence;
+};
+
+// --------
+
+static UString escapeStringForPrettyPrinting(const UString& s)
+{
+ UString escapedString;
+
+ for (int i = 0; i < s.size(); i++) {
+ unsigned short c = s.data()[i].unicode();
+ switch (c) {
+ case '\"':
+ escapedString += "\\\"";
+ break;
+ case '\n':
+ escapedString += "\\n";
+ break;
+ case '\r':
+ escapedString += "\\r";
+ break;
+ case '\t':
+ escapedString += "\\t";
+ break;
+ case '\\':
+ escapedString += "\\\\";
+ break;
+ default:
+ if (c < 128 && isPrintableChar(c))
+ escapedString.append(c);
+ else {
+ char hexValue[7];
+ snprintf(hexValue, 7, "\\u%04x", c);
+ escapedString += hexValue;
+ }
+ }
+ }
+
+ return escapedString;
+}
+
+static const char* operatorString(Operator oper)
+{
+ switch (oper) {
+ case OpEqual:
+ return "=";
+ case OpMultEq:
+ return "*=";
+ case OpDivEq:
+ return "/=";
+ case OpPlusEq:
+ return "+=";
+ case OpMinusEq:
+ return "-=";
+ case OpLShift:
+ return "<<=";
+ case OpRShift:
+ return ">>=";
+ case OpURShift:
+ return ">>>=";
+ case OpAndEq:
+ return "&=";
+ case OpXOrEq:
+ return "^=";
+ case OpOrEq:
+ return "|=";
+ case OpModEq:
+ return "%=";
+ case OpPlusPlus:
+ return "++";
+ case OpMinusMinus:
+ return "--";
+ }
+ ASSERT_NOT_REACHED();
+ return "???";
+}
+
+static bool isParserRoundTripNumber(const UString& string)
+{
+ double number = string.toDouble(false, false);
+ if (isnan(number) || isinf(number))
+ return false;
+ return string == UString::from(number);
+}
+
+// --------
+
+SourceStream& SourceStream::operator<<(char c)
+{
+ m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
+ UChar ch(c);
+ m_string.append(ch);
+ return *this;
+}
+
+SourceStream& SourceStream::operator<<(const char* s)
+{
+ m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
+ m_string += s;
+ return *this;
+}
+
+SourceStream& SourceStream::operator<<(double value)
+{
+ bool needParens = m_numberNeedsParens;
+ m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
+
+ if (needParens)
+ m_string.append('(');
+ m_string += UString::from(value);
+ if (needParens)
+ m_string.append(')');
+
+ return *this;
+}
+
+SourceStream& SourceStream::operator<<(const UString& s)
+{
+ m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
+ m_string += s;
+ return *this;
+}
+
+SourceStream& SourceStream::operator<<(const Identifier& s)
+{
+ m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
+ m_string += s.ustring();
+ return *this;
+}
+
+SourceStream& SourceStream::operator<<(const Node* n)
+{
+ bool needParens = (m_precedence != PrecExpression && n->precedence() > m_precedence) || (m_atStartOfStatement && n->needsParensIfLeftmost());
+ m_precedence = PrecExpression;
+ if (!n)
+ return *this;
+ if (needParens) {
+ m_numberNeedsParens = false;
+ m_string.append('(');
+ }
+ n->streamTo(*this);
+ if (needParens)
+ m_string.append(')');
+ return *this;
+}
+
+SourceStream& SourceStream::operator<<(EndlType)
+{
+ m_numberNeedsParens = false;
+ m_atStartOfStatement = true;
+ m_string.append('\n');
+ m_string.append(m_spacesForIndentation);
+ return *this;
+}
+
+SourceStream& SourceStream::operator<<(IndentType)
+{
+ m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
+ m_spacesForIndentation += " ";
+ return *this;
+}
+
+SourceStream& SourceStream::operator<<(UnindentType)
+{
+ m_numberNeedsParens = false;
+ m_atStartOfStatement = false;
+ m_spacesForIndentation = m_spacesForIndentation.substr(0, m_spacesForIndentation.size() - 2);
+ return *this;
+}
+
+inline SourceStream& SourceStream::operator<<(DotExprType)
+{
+ m_numberNeedsParens = true;
+ return *this;
+}
+
+inline SourceStream& SourceStream::operator<<(Precedence precedence)
+{
+ m_precedence = precedence;
+ return *this;
+}
+
+static void streamLeftAssociativeBinaryOperator(SourceStream& s, Precedence precedence,
+ const char* operatorString, const Node* left, const Node* right)
+{
+ s << precedence << left
+ << ' ' << operatorString << ' '
+ << static_cast<Precedence>(precedence - 1) << right;
+}
+
+template <typename T> static inline void streamLeftAssociativeBinaryOperator(SourceStream& s,
+ Precedence p, const char* o, const RefPtr<T>& l, const RefPtr<T>& r)
+{
+ streamLeftAssociativeBinaryOperator(s, p, o, l.get(), r.get());
+}
+
+static inline void bracketNodeStreamTo(SourceStream& s, const RefPtr<ExpressionNode>& base, const RefPtr<ExpressionNode>& subscript)
+{
+ s << PrecCall << base.get() << "[" << subscript.get() << "]";
+}
+
+static inline void dotNodeStreamTo(SourceStream& s, const RefPtr<ExpressionNode>& base, const Identifier& ident)
+{
+ s << DotExpr << PrecCall << base.get() << "." << ident;
+}
+
+// --------
+
+UString Node::toString() const
+{
+ SourceStream stream;
+ streamTo(stream);
+ return stream.toString();
+}
+
+// --------
+
+void NullNode::streamTo(SourceStream& s) const
+{
+ s << "null";
+}
+
+void FalseNode::streamTo(SourceStream& s) const
+{
+ s << "false";
+}
+
+void TrueNode::streamTo(SourceStream& s) const
+{
+ s << "true";
+}
+
+void PlaceholderTrueNode::streamTo(SourceStream&) const
+{
+}
+
+void NumberNode::streamTo(SourceStream& s) const
+{
+ s << value();
+}
+
+void StringNode::streamTo(SourceStream& s) const
+{
+ s << '"' << escapeStringForPrettyPrinting(m_value) << '"';
+}
+
+void RegExpNode::streamTo(SourceStream& s) const
+{
+ s << '/' << m_regExp->pattern() << '/' << m_regExp->flags();
+}
+
+void ThisNode::streamTo(SourceStream& s) const
+{
+ s << "this";
+}
+
+void ResolveNode::streamTo(SourceStream& s) const
+{
+ s << m_ident;
+}
+
+void ElementNode::streamTo(SourceStream& s) const
+{
+ for (const ElementNode* n = this; n; n = n->m_next.get()) {
+ for (int i = 0; i < n->m_elision; i++)
+ s << ',';
+ s << PrecAssignment << n->m_node;
+ if (n->m_next)
+ s << ',';
+ }
+}
+
+void ArrayNode::streamTo(SourceStream& s) const
+{
+ s << '[' << m_element;
+ for (int i = 0; i < m_elision; i++)
+ s << ',';
+ // Parser consumes one elision comma if there's array elements
+ // present in the expression.
+ if (m_optional && m_element)
+ s << ',';
+ s << ']';
+}
+
+void ObjectLiteralNode::streamTo(SourceStream& s) const
+{
+ if (m_list)
+ s << "{ " << m_list << " }";
+ else
+ s << "{ }";
+}
+
+void PropertyListNode::streamTo(SourceStream& s) const
+{
+ s << m_node;
+ for (const PropertyListNode* n = m_next.get(); n; n = n->m_next.get())
+ s << ", " << n->m_node;
+}
+
+void PropertyNode::streamTo(SourceStream& s) const
+{
+ switch (m_type) {
+ case Constant: {
+ UString propertyName = name().ustring();
+ if (isParserRoundTripNumber(propertyName))
+ s << propertyName;
+ else
+ s << '"' << escapeStringForPrettyPrinting(propertyName) << '"';
+ s << ": " << PrecAssignment << m_assign;
+ break;
+ }
+ case Getter:
+ case Setter: {
+ const FuncExprNode* func = static_cast<const FuncExprNode*>(m_assign.get());
+ if (m_type == Getter)
+ s << "get ";
+ else
+ s << "set ";
+ s << escapeStringForPrettyPrinting(name().ustring())
+ << "(" << func->m_parameter << ')' << func->m_body;
+ break;
+ }
+ }
+}
+
+void BracketAccessorNode::streamTo(SourceStream& s) const
+{
+ bracketNodeStreamTo(s, m_base, m_subscript);
+}
+
+void DotAccessorNode::streamTo(SourceStream& s) const
+{
+ dotNodeStreamTo(s, m_base, m_ident);
+}
+
+void ArgumentListNode::streamTo(SourceStream& s) const
+{
+ s << PrecAssignment << m_expr;
+ for (ArgumentListNode* n = m_next.get(); n; n = n->m_next.get())
+ s << ", " << PrecAssignment << n->m_expr;
+}
+
+void ArgumentsNode::streamTo(SourceStream& s) const
+{
+ s << '(' << m_listNode << ')';
+}
+
+void NewExprNode::streamTo(SourceStream& s) const
+{
+ s << "new " << PrecMember << m_expr << m_args;
+}
+
+void FunctionCallValueNode::streamTo(SourceStream& s) const
+{
+ s << PrecCall << m_expr << m_args;
+}
+
+void FunctionCallResolveNode::streamTo(SourceStream& s) const
+{
+ s << m_ident << m_args;
+}
+
+void FunctionCallBracketNode::streamTo(SourceStream& s) const
+{
+ bracketNodeStreamTo(s, m_base, m_subscript);
+ s << m_args;
+}
+
+void FunctionCallDotNode::streamTo(SourceStream& s) const
+{
+ dotNodeStreamTo(s, m_base, m_ident);
+ s << m_args;
+}
+
+void PostIncResolveNode::streamTo(SourceStream& s) const
+{
+ s << m_ident << "++";
+}
+
+void PostDecResolveNode::streamTo(SourceStream& s) const
+{
+ s << m_ident << "--";
+}
+
+void PostIncBracketNode::streamTo(SourceStream& s) const
+{
+ bracketNodeStreamTo(s, m_base, m_subscript);
+ s << "++";
+}
+
+void PostDecBracketNode::streamTo(SourceStream& s) const
+{
+ bracketNodeStreamTo(s, m_base, m_subscript);
+ s << "--";
+}
+
+void PostIncDotNode::streamTo(SourceStream& s) const
+{
+ dotNodeStreamTo(s, m_base, m_ident);
+ s << "++";
+}
+
+void PostDecDotNode::streamTo(SourceStream& s) const
+{
+ dotNodeStreamTo(s, m_base, m_ident);
+ s << "--";
+}
+
+void PostfixErrorNode::streamTo(SourceStream& s) const
+{
+ s << PrecLeftHandSide << m_expr;
+ if (m_operator == OpPlusPlus)
+ s << "++";
+ else
+ s << "--";
+}
+
+void DeleteResolveNode::streamTo(SourceStream& s) const
+{
+ s << "delete " << m_ident;
+}
+
+void DeleteBracketNode::streamTo(SourceStream& s) const
+{
+ s << "delete ";
+ bracketNodeStreamTo(s, m_base, m_subscript);
+}
+
+void DeleteDotNode::streamTo(SourceStream& s) const
+{
+ s << "delete ";
+ dotNodeStreamTo(s, m_base, m_ident);
+}
+
+void DeleteValueNode::streamTo(SourceStream& s) const
+{
+ s << "delete " << PrecUnary << m_expr;
+}
+
+void VoidNode::streamTo(SourceStream& s) const
+{
+ s << "void " << PrecUnary << m_expr;
+}
+
+void TypeOfValueNode::streamTo(SourceStream& s) const
+{
+ s << "typeof " << PrecUnary << m_expr;
+}
+
+void TypeOfResolveNode::streamTo(SourceStream& s) const
+{
+ s << "typeof " << m_ident;
+}
+
+void PreIncResolveNode::streamTo(SourceStream& s) const
+{
+ s << "++" << m_ident;
+}
+
+void PreDecResolveNode::streamTo(SourceStream& s) const
+{
+ s << "--" << m_ident;
+}
+
+void PreIncBracketNode::streamTo(SourceStream& s) const
+{
+ s << "++";
+ bracketNodeStreamTo(s, m_base, m_subscript);
+}
+
+void PreDecBracketNode::streamTo(SourceStream& s) const
+{
+ s << "--";
+ bracketNodeStreamTo(s, m_base, m_subscript);
+}
+
+void PreIncDotNode::streamTo(SourceStream& s) const
+{
+ s << "++";
+ dotNodeStreamTo(s, m_base, m_ident);
+}
+
+void PreDecDotNode::streamTo(SourceStream& s) const
+{
+ s << "--";
+ dotNodeStreamTo(s, m_base, m_ident);
+}
+
+void PrefixErrorNode::streamTo(SourceStream& s) const
+{
+ if (m_operator == OpPlusPlus)
+ s << "++" << PrecUnary << m_expr;
+ else
+ s << "--" << PrecUnary << m_expr;
+}
+
+void UnaryPlusNode::streamTo(SourceStream& s) const
+{
+ s << "+ " << PrecUnary << m_expr;
+}
+
+void NegateNode::streamTo(SourceStream& s) const
+{
+ s << "- " << PrecUnary << m_expr;
+}
+
+void BitwiseNotNode::streamTo(SourceStream& s) const
+{
+ s << "~" << PrecUnary << m_expr;
+}
+
+void LogicalNotNode::streamTo(SourceStream& s) const
+{
+ s << "!" << PrecUnary << m_expr;
+}
+
+void MultNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "*", m_term1, m_term2);
+}
+
+void DivNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "/", m_term1, m_term2);
+}
+
+void ModNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "%", m_term1, m_term2);
+}
+
+void AddNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "+", m_term1, m_term2);
+}
+
+void SubNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "-", m_term1, m_term2);
+}
+
+void LeftShiftNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "<<", m_term1, m_term2);
+}
+
+void RightShiftNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), ">>", m_term1, m_term2);
+}
+
+void UnsignedRightShiftNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), ">>>", m_term1, m_term2);
+}
+
+void LessNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "<", m_expr1, m_expr2);
+}
+
+void GreaterNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), ">", m_expr1, m_expr2);
+}
+
+void LessEqNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "<=", m_expr1, m_expr2);
+}
+
+void GreaterEqNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), ">=", m_expr1, m_expr2);
+}
+
+void InstanceOfNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "instanceof", m_expr1, m_expr2);
+}
+
+void InNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "in", m_expr1, m_expr2);
+}
+
+void EqualNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "==", m_expr1, m_expr2);
+}
+
+void NotEqualNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "!=", m_expr1, m_expr2);
+}
+
+void StrictEqualNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "===", m_expr1, m_expr2);
+}
+
+void NotStrictEqualNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "!==", m_expr1, m_expr2);
+}
+
+void BitAndNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "&", m_expr1, m_expr2);
+}
+
+void BitXOrNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "^", m_expr1, m_expr2);
+}
+
+void BitOrNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "|", m_expr1, m_expr2);
+}
+
+void LogicalAndNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "&&", m_expr1, m_expr2);
+}
+
+void LogicalOrNode::streamTo(SourceStream& s) const
+{
+ streamLeftAssociativeBinaryOperator(s, precedence(), "||", m_expr1, m_expr2);
+}
+
+void ConditionalNode::streamTo(SourceStream& s) const
+{
+ s << PrecLogicalOr << m_logical
+ << " ? " << PrecAssignment << m_expr1
+ << " : " << PrecAssignment << m_expr2;
+}
+
+void ReadModifyResolveNode::streamTo(SourceStream& s) const
+{
+ s << m_ident << ' ' << operatorString(m_operator) << ' ' << PrecAssignment << m_right;
+}
+
+void AssignResolveNode::streamTo(SourceStream& s) const
+{
+ s << m_ident << " = " << PrecAssignment << m_right;
+}
+
+void ReadModifyBracketNode::streamTo(SourceStream& s) const
+{
+ bracketNodeStreamTo(s, m_base, m_subscript);
+ s << ' ' << operatorString(m_operator) << ' ' << PrecAssignment << m_right;
+}
+
+void AssignBracketNode::streamTo(SourceStream& s) const
+{
+ bracketNodeStreamTo(s, m_base, m_subscript);
+ s << " = " << PrecAssignment << m_right;
+}
+
+void ReadModifyDotNode::streamTo(SourceStream& s) const
+{
+ dotNodeStreamTo(s, m_base, m_ident);
+ s << ' ' << operatorString(m_operator) << ' ' << PrecAssignment << m_right;
+}
+
+void AssignDotNode::streamTo(SourceStream& s) const
+{
+ dotNodeStreamTo(s, m_base, m_ident);
+ s << " = " << PrecAssignment << m_right;
+}
+
+void AssignErrorNode::streamTo(SourceStream& s) const
+{
+ s << PrecLeftHandSide << m_left << ' '
+ << operatorString(m_operator) << ' ' << PrecAssignment << m_right;
+}
+
+void CommaNode::streamTo(SourceStream& s) const
+{
+ s << PrecAssignment << m_expr1 << ", " << PrecAssignment << m_expr2;
+}
+
+void ConstDeclNode::streamTo(SourceStream& s) const
+{
+ s << m_ident;
+ if (m_init)
+ s << " = " << m_init;
+ for (ConstDeclNode* n = m_next.get(); n; n = n->m_next.get()) {
+ s << ", " << m_ident;
+ if (m_init)
+ s << " = " << m_init;
+ }
+}
+
+void ConstStatementNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "const " << m_next << ';';
+}
+
+static inline void statementListStreamTo(const Vector<RefPtr<StatementNode> >& nodes, SourceStream& s)
+{
+ for (Vector<RefPtr<StatementNode> >::const_iterator ptr = nodes.begin(); ptr != nodes.end(); ptr++)
+ s << *ptr;
+}
+
+void BlockNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "{" << Indent;
+ statementListStreamTo(m_children, s);
+ s << Unindent << Endl << "}";
+}
+
+void ScopeNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "{" << Indent;
+
+ bool printedVar = false;
+ for (size_t i = 0; i < m_varStack.size(); ++i) {
+ if (m_varStack[i].second == 0) {
+ if (!printedVar) {
+ s << Endl << "var ";
+ printedVar = true;
+ } else
+ s << ", ";
+ s << m_varStack[i].first;
+ }
+ }
+ if (printedVar)
+ s << ';';
+
+ statementListStreamTo(m_children, s);
+ s << Unindent << Endl << "}";
+}
+
+void EmptyStatementNode::streamTo(SourceStream& s) const
+{
+ s << Endl << ';';
+}
+
+void ExprStatementNode::streamTo(SourceStream& s) const
+{
+ s << Endl << m_expr << ';';
+}
+
+void VarStatementNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "var " << m_expr << ';';
+}
+
+void IfNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "if (" << m_condition << ')' << Indent << m_ifBlock << Unindent;
+}
+
+void IfElseNode::streamTo(SourceStream& s) const
+{
+ IfNode::streamTo(s);
+ s << Endl << "else" << Indent << m_elseBlock << Unindent;
+}
+
+void DoWhileNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "do " << Indent << m_statement << Unindent << Endl
+ << "while (" << m_expr << ");";
+}
+
+void WhileNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "while (" << m_expr << ')' << Indent << m_statement << Unindent;
+}
+
+void ForNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "for ("
+ << (m_expr1WasVarDecl ? "var " : "")
+ << m_expr1
+ << "; " << m_expr2
+ << "; " << m_expr3
+ << ')' << Indent << m_statement << Unindent;
+}
+
+void ForInNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "for (";
+ if (m_identIsVarDecl) {
+ s << "var ";
+ if (m_init)
+ s << m_init;
+ else
+ s << PrecLeftHandSide << m_lexpr;
+ } else
+ s << PrecLeftHandSide << m_lexpr;
+
+ s << " in " << m_expr << ')' << Indent << m_statement << Unindent;
+}
+
+void ContinueNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "continue";
+ if (!m_ident.isNull())
+ s << ' ' << m_ident;
+ s << ';';
+}
+
+void BreakNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "break";
+ if (!m_ident.isNull())
+ s << ' ' << m_ident;
+ s << ';';
+}
+
+void ReturnNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "return";
+ if (m_value)
+ s << ' ' << m_value;
+ s << ';';
+}
+
+void WithNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "with (" << m_expr << ") " << m_statement;
+}
+
+void CaseClauseNode::streamTo(SourceStream& s) const
+{
+ s << Endl;
+ if (m_expr)
+ s << "case " << m_expr;
+ else
+ s << "default";
+ s << ":" << Indent;
+ statementListStreamTo(m_children, s);
+ s << Unindent;
+}
+
+void ClauseListNode::streamTo(SourceStream& s) const
+{
+ for (const ClauseListNode* n = this; n; n = n->getNext())
+ s << n->getClause();
+}
+
+void CaseBlockNode::streamTo(SourceStream& s) const
+{
+ for (const ClauseListNode* n = m_list1.get(); n; n = n->getNext())
+ s << n->getClause();
+ s << m_defaultClause;
+ for (const ClauseListNode* n = m_list2.get(); n; n = n->getNext())
+ s << n->getClause();
+}
+
+void SwitchNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "switch (" << m_expr << ") {"
+ << Indent << m_block << Unindent
+ << Endl << "}";
+}
+
+void LabelNode::streamTo(SourceStream& s) const
+{
+ s << Endl << m_label << ":" << Indent << m_statement << Unindent;
+}
+
+void ThrowNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "throw " << m_expr << ';';
+}
+
+void TryNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "try " << m_tryBlock;
+ if (m_catchBlock)
+ s << Endl << "catch (" << m_exceptionIdent << ')' << m_catchBlock;
+ if (m_finallyBlock)
+ s << Endl << "finally " << m_finallyBlock;
+}
+
+void ParameterNode::streamTo(SourceStream& s) const
+{
+ s << m_ident;
+ for (ParameterNode* n = m_next.get(); n; n = n->m_next.get())
+ s << ", " << n->m_ident;
+}
+
+void FuncDeclNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "function " << m_ident << '(' << m_parameter << ')' << m_body;
+}
+
+void FuncExprNode::streamTo(SourceStream& s) const
+{
+ s << "function " << m_ident << '(' << m_parameter << ')' << m_body;
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/number_object.cpp b/JavaScriptCore/kjs/number_object.cpp
new file mode 100644
index 0000000..94fc7e7
--- /dev/null
+++ b/JavaScriptCore/kjs/number_object.cpp
@@ -0,0 +1,522 @@
+/*
+ * 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 "number_object.h"
+#include "number_object.lut.h"
+
+#include "dtoa.h"
+#include "error_object.h"
+#include "operations.h"
+#include <wtf/Assertions.h>
+#include <wtf/MathExtras.h>
+#include <wtf/Vector.h>
+
+namespace KJS {
+
+// ------------------------------ NumberInstance ----------------------------
+
+const ClassInfo NumberInstance::info = { "Number", 0, 0 };
+
+NumberInstance::NumberInstance(JSObject* proto)
+ : JSWrapperObject(proto)
+{
+}
+
+// ------------------------------ NumberPrototype ---------------------------
+
+static JSValue* numberProtoFuncToString(ExecState*, JSObject*, const List&);
+static JSValue* numberProtoFuncToLocaleString(ExecState*, JSObject*, const List&);
+static JSValue* numberProtoFuncValueOf(ExecState*, JSObject*, const List&);
+static JSValue* numberProtoFuncToFixed(ExecState*, JSObject*, const List&);
+static JSValue* numberProtoFuncToExponential(ExecState*, JSObject*, const List&);
+static JSValue* numberProtoFuncToPrecision(ExecState*, JSObject*, const List&);
+
+// ECMA 15.7.4
+
+NumberPrototype::NumberPrototype(ExecState* exec, ObjectPrototype* objectPrototype, FunctionPrototype* functionPrototype)
+ : NumberInstance(objectPrototype)
+{
+ setInternalValue(jsNumber(0));
+
+ // The constructor will be added later, after NumberObjectImp has been constructed
+
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, exec->propertyNames().toString, numberProtoFuncToString), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toLocaleString, numberProtoFuncToLocaleString), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().valueOf, numberProtoFuncValueOf), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, exec->propertyNames().toFixed, numberProtoFuncToFixed), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, exec->propertyNames().toExponential, numberProtoFuncToExponential), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, exec->propertyNames().toPrecision, numberProtoFuncToPrecision), DontEnum);
+}
+
+// ------------------------------ Functions ---------------------------
+
+// ECMA 15.7.4.2 - 15.7.4.7
+
+static UString integer_part_noexp(double d)
+{
+ int decimalPoint;
+ int sign;
+ char* result = kjs_dtoa(d, 0, 0, &decimalPoint, &sign, NULL);
+ bool resultIsInfOrNan = (decimalPoint == 9999);
+ size_t length = strlen(result);
+
+ UString str = sign ? "-" : "";
+ if (resultIsInfOrNan)
+ str += result;
+ else if (decimalPoint <= 0)
+ str += "0";
+ else {
+ Vector<char, 1024> buf(decimalPoint + 1);
+
+ if (static_cast<int>(length) <= decimalPoint) {
+ strcpy(buf.data(), result);
+ memset(buf.data() + length, '0', decimalPoint - length);
+ } else
+ strncpy(buf.data(), result, decimalPoint);
+
+ buf[decimalPoint] = '\0';
+ str += UString(buf.data());
+ }
+
+ kjs_freedtoa(result);
+
+ return str;
+}
+
+static UString char_sequence(char c, int count)
+{
+ Vector<char, 2048> buf(count + 1, c);
+ buf[count] = '\0';
+
+ return UString(buf.data());
+}
+
+static double intPow10(int e)
+{
+ // This function uses the "exponentiation by squaring" algorithm and
+ // long double to quickly and precisely calculate integer powers of 10.0.
+
+ // This is a handy workaround for <rdar://problem/4494756>
+
+ if (e == 0)
+ return 1.0;
+
+ bool negative = e < 0;
+ unsigned exp = negative ? -e : e;
+
+ long double result = 10.0;
+ bool foundOne = false;
+ for (int bit = 31; bit >= 0; bit--) {
+ if (!foundOne) {
+ if ((exp >> bit) & 1)
+ foundOne = true;
+ } else {
+ result = result * result;
+ if ((exp >> bit) & 1)
+ result = result * 10.0;
+ }
+ }
+
+ if (negative)
+ return static_cast<double>(1.0 / result);
+ return static_cast<double>(result);
+}
+
+
+JSValue* numberProtoFuncToString(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&NumberInstance::info))
+ return throwError(exec, TypeError);
+
+ JSValue* v = static_cast<NumberInstance*>(thisObj)->internalValue();
+
+ double radixAsDouble = args[0]->toInteger(exec); // nan -> 0
+ if (radixAsDouble == 10 || args[0]->isUndefined())
+ return jsString(v->toString(exec));
+
+ if (radixAsDouble < 2 || radixAsDouble > 36)
+ return throwError(exec, RangeError, "toString() radix argument must be between 2 and 36");
+
+ int radix = static_cast<int>(radixAsDouble);
+ const char digits[] = "0123456789abcdefghijklmnopqrstuvwxyz";
+ // INT_MAX results in 1024 characters left of the dot with radix 2
+ // give the same space on the right side. safety checks are in place
+ // unless someone finds a precise rule.
+ char s[2048 + 3];
+ const char* lastCharInString = s + sizeof(s) - 1;
+ double x = v->toNumber(exec);
+ if (isnan(x) || isinf(x))
+ return jsString(UString::from(x));
+
+ bool isNegative = x < 0.0;
+ if (isNegative)
+ x = -x;
+
+ double integerPart = floor(x);
+ char* decimalPoint = s + sizeof(s) / 2;
+
+ // convert integer portion
+ char* p = decimalPoint;
+ double d = integerPart;
+ do {
+ int remainderDigit = static_cast<int>(fmod(d, radix));
+ *--p = digits[remainderDigit];
+ d /= radix;
+ } while ((d <= -1.0 || d >= 1.0) && s < p);
+
+ if (isNegative)
+ *--p = '-';
+ char* startOfResultString = p;
+ ASSERT(s <= startOfResultString);
+
+ d = x - integerPart;
+ p = decimalPoint;
+ const double epsilon = 0.001; // TODO: guessed. base on radix ?
+ bool hasFractionalPart = (d < -epsilon || d > epsilon);
+ if (hasFractionalPart) {
+ *p++ = '.';
+ do {
+ d *= radix;
+ const int digit = static_cast<int>(d);
+ *p++ = digits[digit];
+ d -= digit;
+ } while ((d < -epsilon || d > epsilon) && p < lastCharInString);
+ }
+ *p = '\0';
+ ASSERT(p < s + sizeof(s));
+
+ return jsString(startOfResultString);
+}
+
+JSValue* numberProtoFuncToLocaleString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&NumberInstance::info))
+ return throwError(exec, TypeError);
+
+ // TODO
+ return jsString(static_cast<NumberInstance*>(thisObj)->internalValue()->toString(exec));
+}
+
+JSValue* numberProtoFuncValueOf(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&NumberInstance::info))
+ return throwError(exec, TypeError);
+
+ return static_cast<NumberInstance*>(thisObj)->internalValue()->toJSNumber(exec);
+}
+
+JSValue* numberProtoFuncToFixed(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&NumberInstance::info))
+ return throwError(exec, TypeError);
+
+ JSValue* v = static_cast<NumberInstance*>(thisObj)->internalValue();
+
+ JSValue* fractionDigits = args[0];
+ double df = fractionDigits->toInteger(exec);
+ if (!(df >= 0 && df <= 20))
+ return throwError(exec, RangeError, "toFixed() digits argument must be between 0 and 20");
+ int f = (int)df;
+
+ double x = v->toNumber(exec);
+ if (isnan(x))
+ return jsString("NaN");
+
+ UString s;
+ if (x < 0) {
+ s.append('-');
+ x = -x;
+ } else if (x == -0.0)
+ x = 0;
+
+ if (x >= pow(10.0, 21.0))
+ return jsString(s + UString::from(x));
+
+ const double tenToTheF = pow(10.0, f);
+ double n = floor(x * tenToTheF);
+ if (fabs(n / tenToTheF - x) >= fabs((n + 1) / tenToTheF - x))
+ n++;
+
+ UString m = integer_part_noexp(n);
+
+ int k = m.size();
+ if (k <= f) {
+ UString z;
+ for (int i = 0; i < f + 1 - k; i++)
+ z.append('0');
+ m = z + m;
+ k = f + 1;
+ ASSERT(k == m.size());
+ }
+ int kMinusf = k - f;
+ if (kMinusf < m.size())
+ return jsString(s + m.substr(0, kMinusf) + "." + m.substr(kMinusf));
+ return jsString(s + m.substr(0, kMinusf));
+}
+
+static void fractionalPartToString(char* buf, int& i, const char* result, int resultLength, int fractionalDigits)
+{
+ if (fractionalDigits <= 0)
+ return;
+
+ int fDigitsInResult = static_cast<int>(resultLength) - 1;
+ buf[i++] = '.';
+ if (fDigitsInResult > 0) {
+ if (fractionalDigits < fDigitsInResult) {
+ strncpy(buf + i, result + 1, fractionalDigits);
+ i += fractionalDigits;
+ } else {
+ strcpy(buf + i, result + 1);
+ i += static_cast<int>(resultLength) - 1;
+ }
+ }
+
+ for (int j = 0; j < fractionalDigits - fDigitsInResult; j++)
+ buf[i++] = '0';
+}
+
+static void exponentialPartToString(char* buf, int& i, int decimalPoint)
+{
+ buf[i++] = 'e';
+ buf[i++] = (decimalPoint >= 0) ? '+' : '-';
+ // decimalPoint can't be more than 3 digits decimal given the
+ // nature of float representation
+ int exponential = decimalPoint - 1;
+ if (exponential < 0)
+ exponential *= -1;
+ if (exponential >= 100)
+ buf[i++] = static_cast<char>('0' + exponential / 100);
+ if (exponential >= 10)
+ buf[i++] = static_cast<char>('0' + (exponential % 100) / 10);
+ buf[i++] = static_cast<char>('0' + exponential % 10);
+}
+
+JSValue* numberProtoFuncToExponential(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&NumberInstance::info))
+ return throwError(exec, TypeError);
+
+ JSValue* v = static_cast<NumberInstance*>(thisObj)->internalValue();
+
+ double x = v->toNumber(exec);
+
+ if (isnan(x) || isinf(x))
+ return jsString(UString::from(x));
+
+ JSValue* fractionalDigitsValue = args[0];
+ double df = fractionalDigitsValue->toInteger(exec);
+ if (!(df >= 0 && df <= 20))
+ return throwError(exec, RangeError, "toExponential() argument must between 0 and 20");
+ int fractionalDigits = (int)df;
+ bool includeAllDigits = fractionalDigitsValue->isUndefined();
+
+ int decimalAdjust = 0;
+ if (x && !includeAllDigits) {
+ double logx = floor(log10(fabs(x)));
+ x /= pow(10.0, logx);
+ const double tenToTheF = pow(10.0, fractionalDigits);
+ double fx = floor(x * tenToTheF) / tenToTheF;
+ double cx = ceil(x * tenToTheF) / tenToTheF;
+
+ if (fabs(fx - x) < fabs(cx - x))
+ x = fx;
+ else
+ x = cx;
+
+ decimalAdjust = static_cast<int>(logx);
+ }
+
+ if (isnan(x))
+ return jsString("NaN");
+
+ if (x == -0.0) // (-0.0).toExponential() should print as 0 instead of -0
+ x = 0;
+
+ int decimalPoint;
+ int sign;
+ char* result = kjs_dtoa(x, 0, 0, &decimalPoint, &sign, NULL);
+ size_t resultLength = strlen(result);
+ decimalPoint += decimalAdjust;
+
+ int i = 0;
+ char buf[80]; // digit + '.' + fractionDigits (max 20) + 'e' + sign + exponent (max?)
+ if (sign)
+ buf[i++] = '-';
+
+ if (decimalPoint == 999) // ? 9999 is the magical "result is Inf or NaN" value. what's 999??
+ strcpy(buf + i, result);
+ else {
+ buf[i++] = result[0];
+
+ if (includeAllDigits)
+ fractionalDigits = static_cast<int>(resultLength) - 1;
+
+ fractionalPartToString(buf, i, result, resultLength, fractionalDigits);
+ exponentialPartToString(buf, i, decimalPoint);
+ buf[i++] = '\0';
+ }
+ ASSERT(i <= 80);
+
+ kjs_freedtoa(result);
+
+ return jsString(buf);
+}
+
+JSValue* numberProtoFuncToPrecision(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&NumberInstance::info))
+ return throwError(exec, TypeError);
+
+ JSValue* v = static_cast<NumberInstance*>(thisObj)->internalValue();
+
+ double doublePrecision = args[0]->toIntegerPreserveNaN(exec);
+ double x = v->toNumber(exec);
+ if (args[0]->isUndefined() || isnan(x) || isinf(x))
+ return jsString(v->toString(exec));
+
+ UString s;
+ if (x < 0) {
+ s = "-";
+ x = -x;
+ }
+
+ if (!(doublePrecision >= 1 && doublePrecision <= 21)) // true for NaN
+ return throwError(exec, RangeError, "toPrecision() argument must be between 1 and 21");
+ int precision = (int)doublePrecision;
+
+ int e = 0;
+ UString m;
+ if (x) {
+ e = static_cast<int>(log10(x));
+ double tens = intPow10(e - precision + 1);
+ double n = floor(x / tens);
+ if (n < intPow10(precision - 1)) {
+ e = e - 1;
+ tens = intPow10(e - precision + 1);
+ n = floor(x / tens);
+ }
+
+ if (fabs((n + 1.0) * tens - x) <= fabs(n * tens - x))
+ ++n;
+ // maintain n < 10^(precision)
+ if (n >= intPow10(precision)) {
+ n /= 10.0;
+ e += 1;
+ }
+ ASSERT(intPow10(precision - 1) <= n);
+ ASSERT(n < intPow10(precision));
+
+ m = integer_part_noexp(n);
+ if (e < -6 || e >= precision) {
+ if (m.size() > 1)
+ m = m.substr(0, 1) + "." + m.substr(1);
+ if (e >= 0)
+ return jsString(s + m + "e+" + UString::from(e));
+ return jsString(s + m + "e-" + UString::from(-e));
+ }
+ } else {
+ m = char_sequence('0', precision);
+ e = 0;
+ }
+
+ if (e == precision - 1)
+ return jsString(s + m);
+ if (e >= 0) {
+ if (e + 1 < m.size())
+ return jsString(s + m.substr(0, e + 1) + "." + m.substr(e + 1));
+ return jsString(s + m);
+ }
+ return jsString(s + "0." + char_sequence('0', -(e + 1)) + m);
+}
+
+// ------------------------------ NumberObjectImp ------------------------------
+
+const ClassInfo NumberObjectImp::info = { "Function", &InternalFunctionImp::info, &numberTable };
+
+/* Source for number_object.lut.h
+@begin numberTable 5
+ NaN NumberObjectImp::NaNValue DontEnum|DontDelete|ReadOnly
+ NEGATIVE_INFINITY NumberObjectImp::NegInfinity DontEnum|DontDelete|ReadOnly
+ POSITIVE_INFINITY NumberObjectImp::PosInfinity DontEnum|DontDelete|ReadOnly
+ MAX_VALUE NumberObjectImp::MaxValue DontEnum|DontDelete|ReadOnly
+ MIN_VALUE NumberObjectImp::MinValue DontEnum|DontDelete|ReadOnly
+@end
+*/
+NumberObjectImp::NumberObjectImp(ExecState* exec, FunctionPrototype* funcProto, NumberPrototype* numberProto)
+ : InternalFunctionImp(funcProto, numberProto->classInfo()->className)
+{
+ // Number.Prototype
+ putDirect(exec->propertyNames().prototype, numberProto, DontEnum|DontDelete|ReadOnly);
+
+ // no. of arguments for constructor
+ putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum);
+}
+
+bool NumberObjectImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticValueSlot<NumberObjectImp, InternalFunctionImp>(exec, &numberTable, this, propertyName, slot);
+}
+
+JSValue* NumberObjectImp::getValueProperty(ExecState*, int token) const
+{
+ // ECMA 15.7.3
+ switch (token) {
+ case NaNValue:
+ return jsNaN();
+ case NegInfinity:
+ return jsNumberCell(-Inf);
+ case PosInfinity:
+ return jsNumberCell(Inf);
+ case MaxValue:
+ return jsNumberCell(1.7976931348623157E+308);
+ case MinValue:
+ return jsNumberCell(5E-324);
+ }
+ ASSERT_NOT_REACHED();
+ return jsNull();
+}
+
+bool NumberObjectImp::implementsConstruct() const
+{
+ return true;
+}
+
+// ECMA 15.7.1
+JSObject* NumberObjectImp::construct(ExecState* exec, const List& args)
+{
+ JSObject* proto = exec->lexicalGlobalObject()->numberPrototype();
+ NumberInstance* obj = new NumberInstance(proto);
+
+ // FIXME: Check args[0]->isUndefined() instead of args.isEmpty()?
+ double n = args.isEmpty() ? 0 : args[0]->toNumber(exec);
+ obj->setInternalValue(jsNumber(n));
+ return obj;
+}
+
+// ECMA 15.7.2
+JSValue* NumberObjectImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
+{
+ // FIXME: Check args[0]->isUndefined() instead of args.isEmpty()?
+ return jsNumber(args.isEmpty() ? 0 : args[0]->toNumber(exec));
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/number_object.h b/JavaScriptCore/kjs/number_object.h
new file mode 100644
index 0000000..36befed
--- /dev/null
+++ b/JavaScriptCore/kjs/number_object.h
@@ -0,0 +1,76 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef NUMBER_OBJECT_H_
+#define NUMBER_OBJECT_H_
+
+#include "function_object.h"
+#include "JSWrapperObject.h"
+
+namespace KJS {
+
+ class NumberInstance : public JSWrapperObject {
+ public:
+ NumberInstance(JSObject* prototype);
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+ };
+
+ /**
+ * @internal
+ *
+ * The initial value of Number.prototype (and thus all objects created
+ * with the Number constructor
+ */
+ class NumberPrototype : public NumberInstance {
+ public:
+ NumberPrototype(ExecState*, ObjectPrototype*, FunctionPrototype*);
+ };
+
+ /**
+ * @internal
+ *
+ * The initial value of the the global variable's "Number" property
+ */
+ class NumberObjectImp : public InternalFunctionImp {
+ public:
+ NumberObjectImp(ExecState*, FunctionPrototype*, NumberPrototype*);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject* construct(ExecState*, const List&);
+
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+
+ bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ JSValue* getValueProperty(ExecState*, int token) const;
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+
+ enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue };
+
+ JSObject* construct(const List&);
+ };
+
+} // namespace KJS
+
+#endif // NUMBER_OBJECT_H_
diff --git a/JavaScriptCore/kjs/object.cpp b/JavaScriptCore/kjs/object.cpp
new file mode 100644
index 0000000..9f1c2cf
--- /dev/null
+++ b/JavaScriptCore/kjs/object.cpp
@@ -0,0 +1,660 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ * 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 "object.h"
+
+#include "date_object.h"
+#include "error_object.h"
+#include "lookup.h"
+#include "nodes.h"
+#include "operations.h"
+#include "PropertyNameArray.h"
+#include <math.h>
+#include <wtf/Assertions.h>
+
+// maximum global call stack size. Protects against accidental or
+// malicious infinite recursions. Define to -1 if you want no limit.
+// In real-world testing it appears ok to bump the stack depth count to 500.
+// This of course is dependent on stack frame size.
+#define KJS_MAX_STACK 500
+
+#define JAVASCRIPT_CALL_TRACING 0
+#define JAVASCRIPT_MARK_TRACING 0
+
+#if JAVASCRIPT_CALL_TRACING
+static bool _traceJavaScript = false;
+
+extern "C" {
+ void setTraceJavaScript(bool f)
+ {
+ _traceJavaScript = f;
+ }
+
+ static bool traceJavaScript()
+ {
+ return _traceJavaScript;
+ }
+}
+#endif
+
+namespace KJS {
+
+// ------------------------------ Object ---------------------------------------
+
+JSValue *JSObject::call(ExecState *exec, JSObject *thisObj, const List &args)
+{
+ ASSERT(implementsCall());
+
+#if KJS_MAX_STACK > 0
+ static int depth = 0; // sum of all extant function calls
+
+#if JAVASCRIPT_CALL_TRACING
+ static bool tracing = false;
+ if (traceJavaScript() && !tracing) {
+ tracing = true;
+ for (int i = 0; i < depth; i++)
+ putchar (' ');
+ printf ("*** calling: %s\n", toString(exec).ascii());
+ for (int j = 0; j < args.size(); j++) {
+ for (int i = 0; i < depth; i++)
+ putchar (' ');
+ printf ("*** arg[%d] = %s\n", j, args[j]->toString(exec).ascii());
+ }
+ tracing = false;
+ }
+#endif
+
+ if (++depth > KJS_MAX_STACK) {
+ --depth;
+ return throwError(exec, RangeError, "Maximum call stack size exceeded.");
+ }
+#endif
+
+ JSValue *ret = callAsFunction(exec,thisObj,args);
+
+#if KJS_MAX_STACK > 0
+ --depth;
+#endif
+
+#if JAVASCRIPT_CALL_TRACING
+ if (traceJavaScript() && !tracing) {
+ tracing = true;
+ for (int i = 0; i < depth; i++)
+ putchar (' ');
+ printf ("*** returning: %s\n", ret->toString(exec).ascii());
+ tracing = false;
+ }
+#endif
+
+ return ret;
+}
+
+// ------------------------------ JSObject ------------------------------------
+
+void JSObject::mark()
+{
+ JSCell::mark();
+
+#if JAVASCRIPT_MARK_TRACING
+ static int markStackDepth = 0;
+ markStackDepth++;
+ for (int i = 0; i < markStackDepth; i++)
+ putchar('-');
+
+ printf("%s (%p)\n", className().UTF8String().c_str(), this);
+#endif
+
+ JSValue *proto = _proto;
+ if (!proto->marked())
+ proto->mark();
+
+ _prop.mark();
+
+#if JAVASCRIPT_MARK_TRACING
+ markStackDepth--;
+#endif
+}
+
+JSType JSObject::type() const
+{
+ return ObjectType;
+}
+
+const ClassInfo *JSObject::classInfo() const
+{
+ return 0;
+}
+
+UString JSObject::className() const
+{
+ const ClassInfo *ci = classInfo();
+ if ( ci )
+ return ci->className;
+ return "Object";
+}
+
+JSValue *JSObject::get(ExecState *exec, const Identifier &propertyName) const
+{
+ PropertySlot slot;
+
+ if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot))
+ return slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
+
+ return jsUndefined();
+}
+
+JSValue *JSObject::get(ExecState *exec, unsigned propertyName) const
+{
+ PropertySlot slot;
+ if (const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot))
+ return slot.getValue(exec, const_cast<JSObject *>(this), propertyName);
+
+ return jsUndefined();
+}
+
+bool JSObject::getPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot& slot)
+{
+ JSObject *imp = this;
+
+ while (true) {
+ if (imp->getOwnPropertySlot(exec, propertyName, slot))
+ return true;
+
+ JSValue *proto = imp->_proto;
+ if (!proto->isObject())
+ break;
+
+ imp = static_cast<JSObject *>(proto);
+ }
+
+ return false;
+}
+
+bool JSObject::getOwnPropertySlot(ExecState *exec, unsigned propertyName, PropertySlot& slot)
+{
+ return getOwnPropertySlot(exec, Identifier::from(propertyName), slot);
+}
+
+static void throwSetterError(ExecState *exec)
+{
+ throwError(exec, TypeError, "setting a property that has only a getter");
+}
+
+// ECMA 8.6.2.2
+void JSObject::put(ExecState* exec, const Identifier &propertyName, JSValue *value)
+{
+ ASSERT(value);
+
+ if (propertyName == exec->propertyNames().underscoreProto) {
+ JSObject* proto = value->getObject();
+ while (proto) {
+ if (proto == this)
+ throwError(exec, GeneralError, "cyclic __proto__ value");
+ proto = proto->prototype() ? proto->prototype()->getObject() : 0;
+ }
+
+ setPrototype(value);
+ return;
+ }
+
+ // Check if there are any setters or getters in the prototype chain
+ JSObject *obj = this;
+ bool hasGettersOrSetters = false;
+ while (true) {
+ if (obj->_prop.hasGetterSetterProperties()) {
+ hasGettersOrSetters = true;
+ break;
+ }
+
+ if (!obj->_proto->isObject())
+ break;
+
+ obj = static_cast<JSObject *>(obj->_proto);
+ }
+
+ if (hasGettersOrSetters) {
+ unsigned attributes;
+ if (_prop.get(propertyName, attributes) && attributes & ReadOnly)
+ return;
+
+ obj = this;
+ while (true) {
+ if (JSValue *gs = obj->_prop.get(propertyName, attributes)) {
+ if (attributes & GetterSetter) {
+ JSObject *setterFunc = static_cast<GetterSetterImp *>(gs)->getSetter();
+
+ if (!setterFunc) {
+ throwSetterError(exec);
+ return;
+ }
+
+ List args;
+ args.append(value);
+
+ setterFunc->call(exec, this, args);
+ return;
+ } else {
+ // If there's an existing property on the object or one of its
+ // prototype it should be replaced, so we just break here.
+ break;
+ }
+ }
+
+ if (!obj->_proto->isObject())
+ break;
+
+ obj = static_cast<JSObject *>(obj->_proto);
+ }
+ }
+
+ _prop.put(propertyName, value, 0, true);
+}
+
+void JSObject::put(ExecState* exec, unsigned propertyName, JSValue* value)
+{
+ put(exec, Identifier::from(propertyName), value);
+}
+
+// ECMA 8.6.2.4
+bool JSObject::hasProperty(ExecState *exec, const Identifier &propertyName) const
+{
+ PropertySlot slot;
+ return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
+}
+
+bool JSObject::hasProperty(ExecState *exec, unsigned propertyName) const
+{
+ PropertySlot slot;
+ return const_cast<JSObject *>(this)->getPropertySlot(exec, propertyName, slot);
+}
+
+// ECMA 8.6.2.5
+bool JSObject::deleteProperty(ExecState* /*exec*/, const Identifier &propertyName)
+{
+ unsigned attributes;
+ JSValue *v = _prop.get(propertyName, attributes);
+ if (v) {
+ if ((attributes & DontDelete))
+ return false;
+ _prop.remove(propertyName);
+ if (attributes & GetterSetter)
+ _prop.setHasGetterSetterProperties(_prop.containsGettersOrSetters());
+ return true;
+ }
+
+ // Look in the static hashtable of properties
+ const HashEntry* entry = findPropertyHashEntry(propertyName);
+ if (entry && entry->attr & DontDelete)
+ return false; // this builtin property can't be deleted
+ return true;
+}
+
+bool JSObject::hasOwnProperty(ExecState* exec, const Identifier& propertyName) const
+{
+ PropertySlot slot;
+ return const_cast<JSObject*>(this)->getOwnPropertySlot(exec, propertyName, slot);
+}
+
+bool JSObject::deleteProperty(ExecState *exec, unsigned propertyName)
+{
+ return deleteProperty(exec, Identifier::from(propertyName));
+}
+
+static ALWAYS_INLINE JSValue *tryGetAndCallProperty(ExecState *exec, const JSObject *object, const Identifier &propertyName) {
+ JSValue *v = object->get(exec, propertyName);
+ if (v->isObject()) {
+ JSObject *o = static_cast<JSObject*>(v);
+ if (o->implementsCall()) { // spec says "not primitive type" but ...
+ JSObject *thisObj = const_cast<JSObject*>(object);
+ JSValue* def = o->call(exec, thisObj, exec->emptyList());
+ JSType defType = def->type();
+ ASSERT(defType != GetterSetterType);
+ if (defType != ObjectType)
+ return def;
+ }
+ }
+ return NULL;
+}
+
+bool JSObject::getPrimitiveNumber(ExecState* exec, double& number, JSValue*& result)
+{
+ result = defaultValue(exec, NumberType);
+ number = result->toNumber(exec);
+ return !result->isString();
+}
+
+// ECMA 8.6.2.6
+JSValue* JSObject::defaultValue(ExecState* exec, JSType hint) const
+{
+ /* Prefer String for Date objects */
+ if ((hint == StringType) || (hint != NumberType && _proto == exec->lexicalGlobalObject()->datePrototype())) {
+ if (JSValue* v = tryGetAndCallProperty(exec, this, exec->propertyNames().toString))
+ return v;
+ if (JSValue* v = tryGetAndCallProperty(exec, this, exec->propertyNames().valueOf))
+ return v;
+ } else {
+ if (JSValue* v = tryGetAndCallProperty(exec, this, exec->propertyNames().valueOf))
+ return v;
+ if (JSValue* v = tryGetAndCallProperty(exec, this, exec->propertyNames().toString))
+ return v;
+ }
+
+ if (exec->hadException())
+ return exec->exception();
+
+ return throwError(exec, TypeError, "No default value");
+}
+
+const HashEntry* JSObject::findPropertyHashEntry(const Identifier& propertyName) const
+{
+ for (const ClassInfo *info = classInfo(); info; info = info->parentClass) {
+ if (const HashTable *propHashTable = info->propHashTable) {
+ if (const HashEntry *e = Lookup::findEntry(propHashTable, propertyName))
+ return e;
+ }
+ }
+ return 0;
+}
+
+void JSObject::defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc)
+{
+ JSValue *o = getDirect(propertyName);
+ GetterSetterImp *gs;
+
+ if (o && o->type() == GetterSetterType) {
+ gs = static_cast<GetterSetterImp *>(o);
+ } else {
+ gs = new GetterSetterImp;
+ putDirect(propertyName, gs, GetterSetter);
+ }
+
+ _prop.setHasGetterSetterProperties(true);
+ gs->setGetter(getterFunc);
+}
+
+void JSObject::defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc)
+{
+ JSValue *o = getDirect(propertyName);
+ GetterSetterImp *gs;
+
+ if (o && o->type() == GetterSetterType) {
+ gs = static_cast<GetterSetterImp *>(o);
+ } else {
+ gs = new GetterSetterImp;
+ putDirect(propertyName, gs, GetterSetter);
+ }
+
+ _prop.setHasGetterSetterProperties(true);
+ gs->setSetter(setterFunc);
+}
+
+bool JSObject::implementsConstruct() const
+{
+ return false;
+}
+
+JSObject* JSObject::construct(ExecState*, const List& /*args*/)
+{
+ ASSERT(false);
+ return NULL;
+}
+
+JSObject* JSObject::construct(ExecState* exec, const List& args, const Identifier& /*functionName*/, const UString& /*sourceURL*/, int /*lineNumber*/)
+{
+ return construct(exec, args);
+}
+
+bool JSObject::implementsCall() const
+{
+ return false;
+}
+
+JSValue *JSObject::callAsFunction(ExecState* /*exec*/, JSObject* /*thisObj*/, const List &/*args*/)
+{
+ ASSERT(false);
+ return NULL;
+}
+
+bool JSObject::implementsHasInstance() const
+{
+ return false;
+}
+
+bool JSObject::hasInstance(ExecState* exec, JSValue* value)
+{
+ JSValue* proto = get(exec, exec->propertyNames().prototype);
+ if (!proto->isObject()) {
+ throwError(exec, TypeError, "intanceof called on an object with an invalid prototype property.");
+ return false;
+ }
+
+ if (!value->isObject())
+ return false;
+
+ JSObject* o = static_cast<JSObject*>(value);
+ while ((o = o->prototype()->getObject())) {
+ if (o == proto)
+ return true;
+ }
+ return false;
+}
+
+bool JSObject::propertyIsEnumerable(ExecState*, const Identifier& propertyName) const
+{
+ unsigned attributes;
+
+ if (!getPropertyAttributes(propertyName, attributes))
+ return false;
+ else
+ return !(attributes & DontEnum);
+}
+
+bool JSObject::getPropertyAttributes(const Identifier& propertyName, unsigned& attributes) const
+{
+ if (_prop.get(propertyName, attributes))
+ return true;
+
+ // Look in the static hashtable of properties
+ const HashEntry* e = findPropertyHashEntry(propertyName);
+ if (e) {
+ attributes = e->attr;
+ return true;
+ }
+
+ return false;
+}
+
+void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+{
+ _prop.getEnumerablePropertyNames(propertyNames);
+
+ // Add properties from the static hashtable of properties
+ const ClassInfo *info = classInfo();
+ while (info) {
+ if (info->propHashTable) {
+ int size = info->propHashTable->size;
+ const HashEntry *e = info->propHashTable->entries;
+ for (int i = 0; i < size; ++i, ++e) {
+ if (e->s && !(e->attr & DontEnum))
+ propertyNames.add(e->s);
+ }
+ }
+ info = info->parentClass;
+ }
+ if (_proto->isObject())
+ static_cast<JSObject*>(_proto)->getPropertyNames(exec, propertyNames);
+}
+
+bool JSObject::toBoolean(ExecState*) const
+{
+ return true;
+}
+
+double JSObject::toNumber(ExecState *exec) const
+{
+ JSValue *prim = toPrimitive(exec,NumberType);
+ if (exec->hadException()) // should be picked up soon in nodes.cpp
+ return 0.0;
+ return prim->toNumber(exec);
+}
+
+UString JSObject::toString(ExecState *exec) const
+{
+ JSValue *prim = toPrimitive(exec,StringType);
+ if (exec->hadException()) // should be picked up soon in nodes.cpp
+ return "";
+ return prim->toString(exec);
+}
+
+JSObject *JSObject::toObject(ExecState*) const
+{
+ return const_cast<JSObject*>(this);
+}
+
+void JSObject::putDirect(const Identifier &propertyName, JSValue *value, int attr)
+{
+ _prop.put(propertyName, value, attr);
+}
+
+void JSObject::putDirect(const Identifier &propertyName, int value, int attr)
+{
+ _prop.put(propertyName, jsNumber(value), attr);
+}
+
+void JSObject::removeDirect(const Identifier &propertyName)
+{
+ _prop.remove(propertyName);
+}
+
+void JSObject::putDirectFunction(InternalFunctionImp* func, int attr)
+{
+ putDirect(func->functionName(), func, attr);
+}
+
+void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue **location)
+{
+ GetterSetterImp *gs = static_cast<GetterSetterImp *>(*location);
+ JSObject *getterFunc = gs->getGetter();
+ if (getterFunc)
+ slot.setGetterSlot(this, getterFunc);
+ else
+ slot.setUndefined(this);
+}
+
+// ------------------------------ Error ----------------------------------------
+
+const char * const errorNamesArr[] = {
+ I18N_NOOP("Error"), // GeneralError
+ I18N_NOOP("Evaluation error"), // EvalError
+ I18N_NOOP("Range error"), // RangeError
+ I18N_NOOP("Reference error"), // ReferenceError
+ I18N_NOOP("Syntax error"), // SyntaxError
+ I18N_NOOP("Type error"), // TypeError
+ I18N_NOOP("URI error"), // URIError
+};
+
+const char * const * const Error::errorNames = errorNamesArr;
+
+JSObject *Error::create(ExecState *exec, ErrorType errtype, const UString &message,
+ int lineno, int sourceId, const UString &sourceURL)
+{
+ JSObject *cons;
+ switch (errtype) {
+ case EvalError:
+ cons = exec->lexicalGlobalObject()->evalErrorConstructor();
+ break;
+ case RangeError:
+ cons = exec->lexicalGlobalObject()->rangeErrorConstructor();
+ break;
+ case ReferenceError:
+ cons = exec->lexicalGlobalObject()->referenceErrorConstructor();
+ break;
+ case SyntaxError:
+ cons = exec->lexicalGlobalObject()->syntaxErrorConstructor();
+ break;
+ case TypeError:
+ cons = exec->lexicalGlobalObject()->typeErrorConstructor();
+ break;
+ case URIError:
+ cons = exec->lexicalGlobalObject()->URIErrorConstructor();
+ break;
+ default:
+ cons = exec->lexicalGlobalObject()->errorConstructor();
+ break;
+ }
+
+ List args;
+ if (message.isEmpty())
+ args.append(jsString(errorNames[errtype]));
+ else
+ args.append(jsString(message));
+ JSObject *err = static_cast<JSObject *>(cons->construct(exec,args));
+
+ if (lineno != -1)
+ err->put(exec, "line", jsNumber(lineno));
+ if (sourceId != -1)
+ err->put(exec, "sourceId", jsNumber(sourceId));
+
+ if(!sourceURL.isNull())
+ err->put(exec, "sourceURL", jsString(sourceURL));
+
+ return err;
+}
+
+JSObject *Error::create(ExecState *exec, ErrorType type, const char *message)
+{
+ return create(exec, type, message, -1, -1, NULL);
+}
+
+JSObject *throwError(ExecState *exec, ErrorType type)
+{
+ JSObject *error = Error::create(exec, type, UString(), -1, -1, NULL);
+ exec->setException(error);
+ return error;
+}
+
+JSObject *throwError(ExecState *exec, ErrorType type, const UString &message)
+{
+ JSObject *error = Error::create(exec, type, message, -1, -1, NULL);
+ exec->setException(error);
+ return error;
+}
+
+JSObject *throwError(ExecState *exec, ErrorType type, const char *message)
+{
+ JSObject *error = Error::create(exec, type, message, -1, -1, NULL);
+ exec->setException(error);
+ return error;
+}
+
+JSObject *throwError(ExecState *exec, ErrorType type, const UString &message, int line, int sourceId, const UString &sourceURL)
+{
+ JSObject *error = Error::create(exec, type, message, line, sourceId, sourceURL);
+ exec->setException(error);
+ return error;
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/object.h b/JavaScriptCore/kjs/object.h
new file mode 100644
index 0000000..2d4e010
--- /dev/null
+++ b/JavaScriptCore/kjs/object.h
@@ -0,0 +1,586 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 2006 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_OBJECT_H
+#define KJS_OBJECT_H
+
+#include "CommonIdentifiers.h"
+#include "ExecState.h"
+#include "JSType.h"
+#include "list.h"
+#include "property_map.h"
+#include "property_slot.h"
+#include "scope_chain.h"
+
+namespace KJS {
+
+ class InternalFunctionImp;
+ class PropertyNameArray;
+
+ struct HashEntry;
+ struct HashTable;
+
+ // ECMA 262-3 8.6.1
+ // Property attributes
+ enum Attribute { None = 0,
+ ReadOnly = 1 << 1, // property can be only read, not written
+ DontEnum = 1 << 2, // property doesn't appear in (for .. in ..)
+ DontDelete = 1 << 3, // property can't be deleted
+ Function = 1 << 4, // property is a function - only used by static hashtables
+ GetterSetter = 1 << 5 }; // property is a getter or setter
+
+ /**
+ * Class Information
+ */
+ 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.
+ */
+ const HashTable* propHashTable;
+ };
+
+ // This is an internal value object which stores getter and setter functions
+ // for a property.
+ class GetterSetterImp : public JSCell {
+ public:
+ JSType type() const { return GetterSetterType; }
+
+ GetterSetterImp() : getter(0), setter(0) { }
+
+ virtual JSValue* toPrimitive(ExecState*, JSType preferred = UnspecifiedType) const;
+ virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
+ virtual bool toBoolean(ExecState *exec) const;
+ virtual double toNumber(ExecState *exec) const;
+ virtual UString toString(ExecState *exec) const;
+ virtual JSObject *toObject(ExecState *exec) const;
+
+ virtual void mark();
+
+ JSObject *getGetter() { return getter; }
+ void setGetter(JSObject *g) { getter = g; }
+ JSObject *getSetter() { return setter; }
+ void setSetter(JSObject *s) { setter = s; }
+
+ private:
+ JSObject *getter;
+ JSObject *setter;
+ };
+
+ class JSObject : public JSCell {
+ public:
+ /**
+ * Creates a new JSObject with the specified prototype
+ *
+ * @param proto The prototype
+ */
+ JSObject(JSValue* proto);
+
+ /**
+ * Creates a new JSObject with a prototype of jsNull()
+ * (that is, the ECMAScript "null" value, not a null object pointer).
+ */
+ JSObject();
+
+ virtual void mark();
+ virtual JSType type() const;
+
+ /**
+ * A pointer to a ClassInfo struct for this class. This provides a basic
+ * facility for run-time type information, and can be used to check an
+ * object's class an inheritance (see inherits()). This should
+ * always return a statically declared pointer, or 0 to indicate that
+ * there is no class information.
+ *
+ * This is primarily useful if you have application-defined classes that you
+ * wish to check against for casting purposes.
+ *
+ * For example, to specify the class info for classes FooImp and BarImp,
+ * where FooImp inherits from BarImp, you would add the following in your
+ * class declarations:
+ *
+ * \code
+ * class BarImp : public JSObject {
+ * virtual const ClassInfo *classInfo() const { return &info; }
+ * static const ClassInfo info;
+ * // ...
+ * };
+ *
+ * class FooImp : public JSObject {
+ * virtual const ClassInfo *classInfo() const { return &info; }
+ * static const ClassInfo info;
+ * // ...
+ * };
+ * \endcode
+ *
+ * And in your source file:
+ *
+ * \code
+ * const ClassInfo BarImp::info = { "Bar", 0, 0 }; // no parent class
+ * const ClassInfo FooImp::info = { "Foo", &BarImp::info, 0 };
+ * \endcode
+ *
+ * @see inherits()
+ */
+ virtual const ClassInfo *classInfo() const;
+
+ /**
+ * Checks whether this object inherits from the class with the specified
+ * classInfo() pointer. This requires that both this class and the other
+ * class return a non-NULL pointer for their classInfo() methods (otherwise
+ * it will return false).
+ *
+ * For example, for two JSObject pointers obj1 and obj2, you can check
+ * if obj1's class inherits from obj2's class using the following:
+ *
+ * if (obj1->inherits(obj2->classInfo())) {
+ * // ...
+ * }
+ *
+ * If you have a handle to a statically declared ClassInfo, such as in the
+ * classInfo() example, you can check for inheritance without needing
+ * an instance of the other class:
+ *
+ * if (obj1->inherits(FooImp::info)) {
+ * // ...
+ * }
+ *
+ * @param cinfo The ClassInfo pointer for the class you want to check
+ * inheritance against.
+ * @return true if this object's class inherits from class with the
+ * ClassInfo pointer specified in cinfo
+ */
+ bool inherits(const ClassInfo *cinfo) const;
+
+ // internal properties (ECMA 262-3 8.6.2)
+
+ /**
+ * Returns the prototype of this object. Note that this is not the same as
+ * the "prototype" property.
+ *
+ * See ECMA 8.6.2
+ *
+ * @return The object's prototype
+ */
+ JSValue *prototype() const;
+ void setPrototype(JSValue *proto);
+
+ /**
+ * Returns the class name of the object
+ *
+ * See ECMA 8.6.2
+ *
+ * @return The object's class name
+ */
+ /**
+ * Implementation of the [[Class]] internal property (implemented by all
+ * Objects)
+ *
+ * The default implementation uses classInfo().
+ * You should either implement classInfo(), or
+ * if you simply need a classname, you can reimplement className()
+ * instead.
+ */
+ virtual UString className() const;
+
+ /**
+ * Retrieves the specified property from the object. If neither the object
+ * or any other object in it's prototype chain have the property, this
+ * function will return Undefined.
+ *
+ * See ECMA 8.6.2.1
+ *
+ * @param exec The current execution state
+ * @param propertyName The name of the property to retrieve
+ *
+ * @return The specified property, or Undefined
+ */
+ JSValue *get(ExecState *exec, const Identifier &propertyName) const;
+ JSValue *get(ExecState *exec, unsigned propertyName) const;
+
+ bool getPropertySlot(ExecState *, const Identifier&, PropertySlot&);
+ bool getPropertySlot(ExecState *, unsigned, PropertySlot&);
+
+ virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertySlot(ExecState *, unsigned index, PropertySlot&);
+
+ /**
+ * Sets the specified property.
+ *
+ * See ECMA 8.6.2.2
+ *
+ * @param exec The current execution state
+ * @param propertyName The name of the property to set
+ * @param propertyValue The value to set
+ */
+ virtual void put(ExecState*, const Identifier& propertyName, JSValue* value);
+ virtual void put(ExecState*, unsigned propertyName, JSValue* value);
+
+ /**
+ * Checks if a property is enumerable, that is if it doesn't have the DontEnum
+ * flag set
+ *
+ * See ECMA 15.2.4
+ * @param exec The current execution state
+ * @param propertyName The name of the property
+ * @return true if the property is enumerable, otherwise false
+ */
+ bool propertyIsEnumerable(ExecState *exec, const Identifier &propertyName) const;
+
+ /**
+ * Checks to see whether the object (or any object in it's prototype chain)
+ * has a property with the specified name.
+ *
+ * See ECMA 8.6.2.4
+ *
+ * @param exec The current execution state
+ * @param propertyName The name of the property to check for
+ * @return true if the object has the property, otherwise false
+ */
+ bool hasProperty(ExecState*, const Identifier&) const;
+ bool hasProperty(ExecState*, unsigned) const;
+ bool hasOwnProperty(ExecState*, const Identifier&) const;
+
+ /**
+ * Removes the specified property from the object.
+ *
+ * See ECMA 8.6.2.5
+ *
+ * @param exec The current execution state
+ * @param propertyName The name of the property to delete
+ * @return true if the property was successfully deleted or did not
+ * exist on the object. false if deleting the specified property is not
+ * allowed.
+ */
+ virtual bool deleteProperty(ExecState *exec, const Identifier &propertyName);
+ virtual bool deleteProperty(ExecState *exec, unsigned propertyName);
+
+ /**
+ * Converts the object into a primitive value. The value return may differ
+ * depending on the supplied hint
+ *
+ * See ECMA 8.6.2.6
+ *
+ * @param exec The current execution state
+ * @param hint The desired primitive type to convert to
+ * @return A primitive value converted from the objetc. Note that the
+ * type of primitive value returned may not be the same as the requested
+ * hint.
+ */
+ /**
+ * Implementation of the [[DefaultValue]] internal property (implemented by
+ * all Objects)
+ */
+ virtual JSValue *defaultValue(ExecState *exec, JSType hint) const;
+
+ /**
+ * Whether or not the object implements the construct() method. If this
+ * returns false you should not call the construct() method on this
+ * object (typically, an assertion will fail to indicate this).
+ *
+ * @return true if this object implements the construct() method, otherwise
+ * false
+ */
+ virtual bool implementsConstruct() const;
+
+ /**
+ * Creates a new object based on this object. Typically this means the
+ * following:
+ * 1. A new object is created
+ * 2. The prototype of the new object is set to the value of this object's
+ * "prototype" property
+ * 3. The call() method of this object is called, with the new object
+ * passed as the this value
+ * 4. The new object is returned
+ *
+ * In some cases, Host objects may differ from these semantics, although
+ * this is discouraged.
+ *
+ * If an error occurs during construction, the execution state's exception
+ * will be set. This can be tested for with ExecState::hadException().
+ * Under some circumstances, the exception object may also be returned.
+ *
+ * Note: This function should not be called if implementsConstruct() returns
+ * false, in which case it will result in an assertion failure.
+ *
+ * @param exec The current execution state
+ * @param args The arguments to be passed to call() once the new object has
+ * been created
+ * @return The newly created &amp; initialized object
+ */
+ /**
+ * Implementation of the [[Construct]] internal property
+ */
+ virtual JSObject* construct(ExecState* exec, const List& args);
+ virtual JSObject* construct(ExecState* exec, const List& args, const Identifier& functionName, const UString& sourceURL, int lineNumber);
+
+ /**
+ * Whether or not the object implements the call() method. If this returns
+ * false you should not call the call() method on this object (typically,
+ * an assertion will fail to indicate this).
+ *
+ * @return true if this object implements the call() method, otherwise
+ * false
+ */
+ virtual bool implementsCall() const;
+
+ /**
+ * Calls this object as if it is a function.
+ *
+ * Note: This function should not be called if implementsCall() returns
+ * false, in which case it will result in an assertion failure.
+ *
+ * See ECMA 8.6.2.3
+ *
+ * @param exec The current execution state
+ * @param thisObj The obj to be used as "this" within function execution.
+ * Note that in most cases this will be different from the C++ "this"
+ * object. For example, if the ECMAScript code "window.location->toString()"
+ * is executed, call() will be invoked on the C++ object which implements
+ * the toString method, with the thisObj being window.location
+ * @param args List of arguments to be passed to the function
+ * @return The return value from the function
+ */
+ JSValue *call(ExecState *exec, JSObject *thisObj, const List &args);
+ virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
+
+ /**
+ * Whether or not the object implements the hasInstance() method. If this
+ * returns false you should not call the hasInstance() method on this
+ * object (typically, an assertion will fail to indicate this).
+ *
+ * @return true if this object implements the hasInstance() method,
+ * otherwise false
+ */
+ virtual bool implementsHasInstance() const;
+
+ /**
+ * Checks whether value delegates behavior to this object. Used by the
+ * instanceof operator.
+ *
+ * @param exec The current execution state
+ * @param value The value to check
+ * @return true if value delegates behavior to this object, otherwise
+ * false
+ */
+ virtual bool hasInstance(ExecState *exec, JSValue *value);
+
+ virtual void getPropertyNames(ExecState*, PropertyNameArray&);
+
+ virtual JSValue* toPrimitive(ExecState*, JSType preferredType = UnspecifiedType) const;
+ virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue*& value);
+ virtual bool toBoolean(ExecState *exec) const;
+ virtual double toNumber(ExecState *exec) const;
+ virtual UString toString(ExecState *exec) const;
+ virtual JSObject *toObject(ExecState *exec) const;
+
+ bool getPropertyAttributes(const Identifier& propertyName, unsigned& attributes) const;
+
+ // WebCore uses this to make document.all and style.filter undetectable
+ virtual bool masqueradeAsUndefined() const { return false; }
+
+ // This get function only looks at the property map.
+ // This is used e.g. by lookupOrCreateFunction (to cache a function, we don't want
+ // to look up in the prototype, it might already exist there)
+ JSValue *getDirect(const Identifier& propertyName) const
+ { return _prop.get(propertyName); }
+ JSValue **getDirectLocation(const Identifier& propertyName)
+ { return _prop.getLocation(propertyName); }
+ void putDirect(const Identifier &propertyName, JSValue *value, int attr = 0);
+ void putDirect(const Identifier &propertyName, int value, int attr = 0);
+ void removeDirect(const Identifier &propertyName);
+
+ // convenience to add a function property under the function's own built-in name
+ void putDirectFunction(InternalFunctionImp*, int attr = 0);
+
+ void fillGetterPropertySlot(PropertySlot& slot, JSValue **location);
+
+ void defineGetter(ExecState *exec, const Identifier& propertyName, JSObject *getterFunc);
+ void defineSetter(ExecState *exec, const Identifier& propertyName, JSObject *setterFunc);
+
+ void saveProperties(SavedProperties &p) const { _prop.save(p); }
+ void restoreProperties(const SavedProperties &p) { _prop.restore(p); }
+
+ virtual bool isActivationObject() const { return false; }
+ virtual bool isGlobalObject() const { return false; }
+
+ protected:
+ PropertyMap _prop;
+
+ private:
+ const HashEntry* findPropertyHashEntry( const Identifier& propertyName ) const;
+ JSValue *_proto;
+ };
+
+ /**
+ * Types of Native Errors available. For custom errors, GeneralError
+ * should be used.
+ */
+ enum ErrorType { GeneralError = 0,
+ EvalError = 1,
+ RangeError = 2,
+ ReferenceError = 3,
+ SyntaxError = 4,
+ TypeError = 5,
+ URIError = 6};
+
+ /**
+ * @short Factory methods for error objects.
+ */
+ class Error {
+ public:
+ /**
+ * Factory method for error objects.
+ *
+ * @param exec The current execution state
+ * @param errtype Type of error.
+ * @param message Optional error message.
+ * @param lineNumber Optional line number.
+ * @param sourceId Optional source id.
+ * @param sourceURL Optional source URL.
+ */
+ static JSObject *create(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL);
+ static JSObject *create(ExecState *, ErrorType, const char *message);
+
+ /**
+ * Array of error names corresponding to ErrorType
+ */
+ static const char * const * const errorNames;
+ };
+
+JSObject *throwError(ExecState *, ErrorType, const UString &message, int lineNumber, int sourceId, const UString &sourceURL);
+JSObject *throwError(ExecState *, ErrorType, const UString &message);
+JSObject *throwError(ExecState *, ErrorType, const char *message);
+JSObject *throwError(ExecState *, ErrorType);
+
+inline JSObject::JSObject(JSValue* proto)
+ : _proto(proto)
+{
+ ASSERT(proto);
+}
+
+inline JSObject::JSObject()
+ : _proto(jsNull())
+{
+}
+
+inline JSValue *JSObject::prototype() const
+{
+ return _proto;
+}
+
+inline void JSObject::setPrototype(JSValue *proto)
+{
+ ASSERT(proto);
+ _proto = proto;
+}
+
+inline bool JSObject::inherits(const ClassInfo *info) const
+{
+ for (const ClassInfo *ci = classInfo(); ci; ci = ci->parentClass)
+ if (ci == info)
+ return true;
+ return false;
+}
+
+// this method is here to be after the inline declaration of JSObject::inherits
+inline bool JSCell::isObject(const ClassInfo *info) const
+{
+ return isObject() && static_cast<const JSObject *>(this)->inherits(info);
+}
+
+// this method is here to be after the inline declaration of JSCell::isObject
+inline bool JSValue::isObject(const ClassInfo *c) const
+{
+ return !JSImmediate::isImmediate(this) && asCell()->isObject(c);
+}
+
+// It may seem crazy to inline a function this large but it makes a big difference
+// since this is function very hot in variable lookup
+inline bool JSObject::getPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ JSObject *object = this;
+ while (true) {
+ if (object->getOwnPropertySlot(exec, propertyName, slot))
+ return true;
+
+ JSValue *proto = object->_proto;
+ if (!proto->isObject())
+ return false;
+
+ object = static_cast<JSObject *>(proto);
+ }
+}
+
+// It may seem crazy to inline a function this large, especially a virtual function,
+// but it makes a big difference to property lookup that derived classes can inline their
+// base class call to this.
+ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (JSValue **location = getDirectLocation(propertyName)) {
+ if (_prop.hasGetterSetterProperties() && location[0]->type() == GetterSetterType)
+ fillGetterPropertySlot(slot, location);
+ else
+ slot.setValueSlot(this, location);
+ return true;
+ }
+
+ // non-standard Netscape extension
+ if (propertyName == exec->propertyNames().underscoreProto) {
+ slot.setValueSlot(this, &_proto);
+ return true;
+ }
+
+ return false;
+}
+
+inline void ScopeChain::release()
+{
+ // This function is only called by deref(),
+ // Deref ensures these conditions are true.
+ ASSERT(_node && _node->refCount == 0);
+ ScopeChainNode *n = _node;
+ do {
+ ScopeChainNode *next = n->next;
+ delete n;
+ n = next;
+ } while (n && --n->refCount == 0);
+}
+
+inline JSValue* JSObject::toPrimitive(ExecState* exec, JSType preferredType) const
+{
+ return defaultValue(exec, preferredType);
+}
+
+} // namespace
+
+#endif // KJS_OBJECT_H
diff --git a/JavaScriptCore/kjs/object_object.cpp b/JavaScriptCore/kjs/object_object.cpp
new file mode 100644
index 0000000..90eaa93
--- /dev/null
+++ b/JavaScriptCore/kjs/object_object.cpp
@@ -0,0 +1,216 @@
+/*
+ * 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 "object_object.h"
+
+#include "JSGlobalObject.h"
+#include "operations.h"
+#include "function_object.h"
+#include <stdio.h>
+
+namespace KJS {
+
+// ------------------------------ ObjectPrototype --------------------------------
+
+static JSValue* objectProtoFuncValueOf(ExecState*, JSObject*, const List&);
+static JSValue* objectProtoFuncHasOwnProperty(ExecState*, JSObject*, const List&);
+static JSValue* objectProtoFuncIsPrototypeOf(ExecState*, JSObject*, const List&);
+static JSValue* objectProtoFuncDefineGetter(ExecState*, JSObject*, const List&);
+static JSValue* objectProtoFuncDefineSetter(ExecState*, JSObject*, const List&);
+static JSValue* objectProtoFuncLookupGetter(ExecState*, JSObject*, const List&);
+static JSValue* objectProtoFuncLookupSetter(ExecState*, JSObject*, const List&);
+static JSValue* objectProtoFuncPropertyIsEnumerable(ExecState*, JSObject*, const List&);
+static JSValue* objectProtoFuncToLocaleString(ExecState*, JSObject*, const List&);
+
+ObjectPrototype::ObjectPrototype(ExecState* exec, FunctionPrototype* functionPrototype)
+ : JSObject() // [[Prototype]] is null
+{
+ static const Identifier* hasOwnPropertyPropertyName = new Identifier("hasOwnProperty");
+ static const Identifier* propertyIsEnumerablePropertyName = new Identifier("propertyIsEnumerable");
+ static const Identifier* isPrototypeOfPropertyName = new Identifier("isPrototypeOf");
+ static const Identifier* defineGetterPropertyName = new Identifier("__defineGetter__");
+ static const Identifier* defineSetterPropertyName = new Identifier("__defineSetter__");
+ static const Identifier* lookupGetterPropertyName = new Identifier("__lookupGetter__");
+ static const Identifier* lookupSetterPropertyName = new Identifier("__lookupSetter__");
+
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toString, objectProtoFuncToString), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toLocaleString, objectProtoFuncToLocaleString), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().valueOf, objectProtoFuncValueOf), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *hasOwnPropertyPropertyName, objectProtoFuncHasOwnProperty), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *propertyIsEnumerablePropertyName, objectProtoFuncPropertyIsEnumerable), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *isPrototypeOfPropertyName, objectProtoFuncIsPrototypeOf), DontEnum);
+
+ // Mozilla extensions
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 2, *defineGetterPropertyName, objectProtoFuncDefineGetter), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 2, *defineSetterPropertyName, objectProtoFuncDefineSetter), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *lookupGetterPropertyName, objectProtoFuncLookupGetter), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 1, *lookupSetterPropertyName, objectProtoFuncLookupSetter), DontEnum);
+}
+
+
+// ------------------------------ Functions --------------------------------
+
+// ECMA 15.2.4.2, 15.2.4.4, 15.2.4.5, 15.2.4.7
+
+JSValue* objectProtoFuncValueOf(ExecState*, JSObject* thisObj, const List&)
+{
+ return thisObj;
+}
+
+JSValue* objectProtoFuncHasOwnProperty(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ return jsBoolean(thisObj->hasOwnProperty(exec, Identifier(args[0]->toString(exec))));
+}
+
+JSValue* objectProtoFuncIsPrototypeOf(ExecState*, JSObject* thisObj, const List& args)
+{
+ if (!args[0]->isObject())
+ return jsBoolean(false);
+
+ JSValue* v = static_cast<JSObject*>(args[0])->prototype();
+
+ while (true) {
+ if (!v->isObject())
+ return jsBoolean(false);
+ if (thisObj == static_cast<JSObject*>(v))
+ return jsBoolean(true);
+ v = static_cast<JSObject*>(v)->prototype();
+ }
+}
+
+JSValue* objectProtoFuncDefineGetter(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!args[1]->isObject() || !static_cast<JSObject*>(args[1])->implementsCall())
+ return throwError(exec, SyntaxError, "invalid getter usage");
+
+ thisObj->defineGetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1]));
+ return jsUndefined();
+}
+
+JSValue* objectProtoFuncDefineSetter(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!args[1]->isObject() || !static_cast<JSObject*>(args[1])->implementsCall())
+ return throwError(exec, SyntaxError, "invalid setter usage");
+
+ thisObj->defineSetter(exec, Identifier(args[0]->toString(exec)), static_cast<JSObject *>(args[1]));
+ return jsUndefined();
+}
+
+JSValue* objectProtoFuncLookupGetter(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ Identifier propertyName = Identifier(args[0]->toString(exec));
+ JSObject* obj = thisObj;
+ while (true) {
+ JSValue* v = obj->getDirect(propertyName);
+ if (v) {
+ if (v->type() != GetterSetterType)
+ return jsUndefined();
+ JSObject* funcObj = static_cast<GetterSetterImp*>(v)->getGetter();
+ if (!funcObj)
+ return jsUndefined();
+ return funcObj;
+ }
+
+ if (!obj->prototype() || !obj->prototype()->isObject())
+ return jsUndefined();
+ obj = static_cast<JSObject*>(obj->prototype());
+ }
+}
+
+JSValue* objectProtoFuncLookupSetter(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ Identifier propertyName = Identifier(args[0]->toString(exec));
+ JSObject* obj = thisObj;
+ while (true) {
+ JSValue* v = obj->getDirect(propertyName);
+ if (v) {
+ if (v->type() != GetterSetterType)
+ return jsUndefined();
+ JSObject* funcObj = static_cast<GetterSetterImp*>(v)->getSetter();
+ if (!funcObj)
+ return jsUndefined();
+ return funcObj;
+ }
+
+ if (!obj->prototype() || !obj->prototype()->isObject())
+ return jsUndefined();
+ obj = static_cast<JSObject*>(obj->prototype());
+ }
+}
+
+JSValue* objectProtoFuncPropertyIsEnumerable(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ return jsBoolean(thisObj->propertyIsEnumerable(exec, Identifier(args[0]->toString(exec))));
+}
+
+JSValue* objectProtoFuncToLocaleString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ return jsString(thisObj->toString(exec));
+}
+
+JSValue* objectProtoFuncToString(ExecState*, JSObject* thisObj, const List&)
+{
+ return jsString("[object " + thisObj->className() + "]");
+}
+
+// ------------------------------ ObjectObjectImp --------------------------------
+
+ObjectObjectImp::ObjectObjectImp(ExecState* exec, ObjectPrototype* objProto, FunctionPrototype* funcProto)
+ : InternalFunctionImp(funcProto, "Object")
+{
+ // ECMA 15.2.3.1
+ putDirect(exec->propertyNames().prototype, objProto, DontEnum|DontDelete|ReadOnly);
+
+ // no. of arguments for constructor
+ putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum);
+}
+
+
+bool ObjectObjectImp::implementsConstruct() const
+{
+ return true;
+}
+
+// ECMA 15.2.2
+JSObject* ObjectObjectImp::construct(ExecState* exec, const List& args)
+{
+ JSValue* arg = args[0];
+ switch (arg->type()) {
+ case StringType:
+ case BooleanType:
+ case NumberType:
+ case ObjectType:
+ return arg->toObject(exec);
+ case NullType:
+ case UndefinedType:
+ return new JSObject(exec->lexicalGlobalObject()->objectPrototype());
+ default:
+ ASSERT_NOT_REACHED();
+ return 0;
+ }
+}
+
+JSValue* ObjectObjectImp::callAsFunction(ExecState* exec, JSObject* /*thisObj*/, const List &args)
+{
+ return construct(exec, args);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/object_object.h b/JavaScriptCore/kjs/object_object.h
new file mode 100644
index 0000000..0ee5482
--- /dev/null
+++ b/JavaScriptCore/kjs/object_object.h
@@ -0,0 +1,57 @@
+/*
+ * 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 _OBJECT_OBJECT_H_
+#define _OBJECT_OBJECT_H_
+
+#include "function.h"
+
+namespace KJS {
+
+ /**
+ * @internal
+ *
+ * The initial value of Object.prototype (and thus all objects created
+ * with the Object constructor
+ */
+ class ObjectPrototype : public JSObject {
+ public:
+ ObjectPrototype(ExecState*, FunctionPrototype*);
+ };
+
+ JSValue* objectProtoFuncToString(ExecState*, JSObject*, const List&);
+
+ /**
+ * @internal
+ *
+ * The initial value of the the global variable's "Object" property
+ */
+ class ObjectObjectImp : public InternalFunctionImp {
+ public:
+ ObjectObjectImp(ExecState*, ObjectPrototype*, FunctionPrototype*);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject* construct(ExecState*, const List&);
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+ };
+
+} // namespace KJS
+
+#endif // _OBJECT_OBJECT_H_
diff --git a/JavaScriptCore/kjs/operations.cpp b/JavaScriptCore/kjs/operations.cpp
new file mode 100644
index 0000000..d2b3892
--- /dev/null
+++ b/JavaScriptCore/kjs/operations.cpp
@@ -0,0 +1,128 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.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 "operations.h"
+
+#include "internal.h"
+#include "object.h"
+#include <math.h>
+#include <stdio.h>
+#include <wtf/MathExtras.h>
+
+#if HAVE(FLOAT_H)
+#include <float.h>
+#endif
+
+namespace KJS {
+
+// ECMA 11.9.3
+bool equal(ExecState *exec, JSValue *v1, JSValue *v2)
+{
+ JSType t1 = v1->type();
+ JSType t2 = v2->type();
+
+ if (t1 != t2) {
+ if (t1 == UndefinedType)
+ t1 = NullType;
+ if (t2 == UndefinedType)
+ t2 = NullType;
+
+ if (t1 == BooleanType)
+ t1 = NumberType;
+ if (t2 == BooleanType)
+ t2 = NumberType;
+
+ if (t1 == NumberType && t2 == StringType) {
+ // use toNumber
+ } else if (t1 == StringType && t2 == NumberType)
+ t1 = NumberType;
+ // use toNumber
+ else {
+ if ((t1 == StringType || t1 == NumberType) && t2 == ObjectType) {
+ v2 = v2->toPrimitive(exec);
+ if (exec->hadException())
+ return false;
+ return equal(exec, v1, v2);
+ }
+ if (t1 == NullType && t2 == ObjectType)
+ return static_cast<JSObject *>(v2)->masqueradeAsUndefined();
+ if (t1 == ObjectType && (t2 == StringType || t2 == NumberType)) {
+ v1 = v1->toPrimitive(exec);
+ if (exec->hadException())
+ return false;
+ return equal(exec, v1, v2);
+ }
+ if (t1 == ObjectType && t2 == NullType)
+ return static_cast<JSObject *>(v1)->masqueradeAsUndefined();
+ if (t1 != t2)
+ return false;
+ }
+ }
+
+ if (t1 == UndefinedType || t1 == NullType)
+ return true;
+
+ if (t1 == NumberType) {
+ double d1 = v1->toNumber(exec);
+ double d2 = v2->toNumber(exec);
+ return d1 == d2;
+ }
+
+ if (t1 == StringType)
+ return static_cast<StringImp*>(v1)->value() == static_cast<StringImp*>(v2)->value();
+
+ if (t1 == BooleanType)
+ return v1->toBoolean(exec) == v2->toBoolean(exec);
+
+ // types are Object
+ return v1 == v2;
+}
+
+bool strictEqual(ExecState *exec, JSValue *v1, JSValue *v2)
+{
+ JSType t1 = v1->type();
+ JSType t2 = v2->type();
+
+ if (t1 != t2)
+ return false;
+ if (t1 == UndefinedType || t1 == NullType)
+ return true;
+ if (t1 == NumberType) {
+ double n1 = v1->toNumber(exec);
+ double n2 = v2->toNumber(exec);
+ if (n1 == n2)
+ return true;
+ return false;
+ } else if (t1 == StringType)
+ return v1->toString(exec) == v2->toString(exec);
+ else if (t2 == BooleanType)
+ return v1->toBoolean(exec) == v2->toBoolean(exec);
+
+ if (v1 == v2)
+ return true;
+ /* TODO: joined objects */
+
+ return false;
+}
+
+}
diff --git a/JavaScriptCore/kjs/operations.h b/JavaScriptCore/kjs/operations.h
new file mode 100644
index 0000000..96656f0
--- /dev/null
+++ b/JavaScriptCore/kjs/operations.h
@@ -0,0 +1,35 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _KJS_OPERATIONS_H_
+#define _KJS_OPERATIONS_H_
+
+namespace KJS {
+
+ class ExecState;
+ class JSValue;
+
+ bool equal(ExecState *exec, JSValue *v1, JSValue *v2);
+ bool strictEqual(ExecState *exec, JSValue *v1, JSValue *v2);
+}
+
+#endif
diff --git a/JavaScriptCore/kjs/property_map.cpp b/JavaScriptCore/kjs/property_map.cpp
new file mode 100644
index 0000000..1da4917
--- /dev/null
+++ b/JavaScriptCore/kjs/property_map.cpp
@@ -0,0 +1,850 @@
+/*
+ * 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.
+ *
+ */
+
+#include "config.h"
+#include "property_map.h"
+
+#include "object.h"
+#include "protect.h"
+#include "PropertyNameArray.h"
+#include <algorithm>
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/HashTable.h>
+#include <wtf/Vector.h>
+
+using std::max;
+using WTF::doubleHash;
+
+#ifndef NDEBUG
+#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
+#define DUMP_PROPERTYMAP_STATS 0
+#else
+#define DO_PROPERTYMAP_CONSTENCY_CHECK 0
+#define DUMP_PROPERTYMAP_STATS 0
+#endif
+
+#define USE_SINGLE_ENTRY 1
+
+// 2/28/2006 ggaren: command-line JS iBench says that USE_SINGLE_ENTRY is a
+// 3.2% performance boost.
+
+namespace KJS {
+
+// Choose a number for the following so that most property maps are smaller,
+// but it's not going to blow out the stack to allocate this number of pointers.
+static const int smallMapThreshold = 1024;
+
+// The point at which the function call overhead of the qsort implementation
+// becomes small compared to the inefficiency of insertion sort.
+static const unsigned tinyMapThreshold = 20;
+
+#if DUMP_PROPERTYMAP_STATS
+
+static int numProbes;
+static int numCollisions;
+static int numRehashes;
+static int numRemoves;
+
+struct PropertyMapStatisticsExitLogger { ~PropertyMapStatisticsExitLogger(); };
+
+static PropertyMapStatisticsExitLogger logger;
+
+PropertyMapStatisticsExitLogger::~PropertyMapStatisticsExitLogger()
+{
+ printf("\nKJS::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
+
+struct PropertyMapEntry {
+ UString::Rep* key;
+ JSValue* value;
+ unsigned attributes;
+ unsigned index;
+
+ PropertyMapEntry(UString::Rep* k, JSValue* v, int a)
+ : key(k), value(v), attributes(a), index(0)
+ {
+ }
+};
+
+// lastIndexUsed is an ever-increasing index used to identify the order items
+// were inserted into the property map. It's required that getEnumerablePropertyNames
+// return the properties in the order they were added for compatibility with other
+// browsers' JavaScript implementations.
+struct PropertyMapHashTable {
+ unsigned sizeMask;
+ unsigned size;
+ unsigned keyCount;
+ unsigned deletedSentinelCount;
+ unsigned lastIndexUsed;
+ unsigned entryIndicies[1];
+
+ PropertyMapEntry* entries()
+ {
+ // The entries vector comes after the indices vector.
+ // The 0th item in the entries vector is not really used; it has to
+ // have a 0 in its key to allow the hash table lookup to handle deleted
+ // sentinels without any special-case code, but the other fields are unused.
+ return reinterpret_cast<PropertyMapEntry*>(&entryIndicies[size]);
+ }
+
+ static size_t allocationSize(unsigned size)
+ {
+ // We never let a hash table get more than half full,
+ // So the number of indices we need is the size of the hash table.
+ // But the number of entries is half that (plus one for the deleted sentinel).
+ return sizeof(PropertyMapHashTable)
+ + (size - 1) * sizeof(unsigned)
+ + (1 + size / 2) * sizeof(PropertyMapEntry);
+ }
+};
+
+static const unsigned emptyEntryIndex = 0;
+static const unsigned deletedSentinelIndex = 1;
+
+SavedProperties::SavedProperties()
+ : count(0)
+{
+}
+
+SavedProperties::~SavedProperties()
+{
+}
+
+#if !DO_PROPERTYMAP_CONSTENCY_CHECK
+
+inline void PropertyMap::checkConsistency()
+{
+}
+
+#endif
+
+PropertyMap::~PropertyMap()
+{
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ if (m_singleEntryKey)
+ m_singleEntryKey->deref();
+#endif
+ return;
+ }
+
+ unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; i++) {
+ if (UString::Rep* key = m_u.table->entries()[i].key)
+ key->deref();
+ }
+ fastFree(m_u.table);
+}
+
+void PropertyMap::clear()
+{
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ if (m_singleEntryKey) {
+ m_singleEntryKey->deref();
+ m_singleEntryKey = 0;
+ }
+#endif
+ return;
+ }
+
+ unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; i++) {
+ if (UString::Rep* key = m_u.table->entries()[i].key)
+ key->deref();
+ }
+ for (unsigned i = 0; i < m_u.table->size; i++)
+ m_u.table->entryIndicies[i] = emptyEntryIndex;
+ m_u.table->keyCount = 0;
+ m_u.table->deletedSentinelCount = 0;
+}
+
+JSValue* PropertyMap::get(const Identifier& name, unsigned& attributes) const
+{
+ ASSERT(!name.isNull());
+
+ UString::Rep* rep = name._ustring.rep();
+
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ if (rep == m_singleEntryKey) {
+ attributes = m_singleEntryAttributes;
+ return m_u.singleEntryValue;
+ }
+#endif
+ return 0;
+ }
+
+ unsigned i = rep->computedHash();
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+#endif
+
+ unsigned entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ if (entryIndex == emptyEntryIndex)
+ return 0;
+
+ if (rep == m_u.table->entries()[entryIndex - 1].key) {
+ attributes = m_u.table->entries()[entryIndex - 1].attributes;
+ return m_u.table->entries()[entryIndex - 1].value;
+ }
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+
+ unsigned k = 1 | doubleHash(rep->computedHash());
+
+ while (1) {
+ i += k;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+
+ entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ if (entryIndex == emptyEntryIndex)
+ return 0;
+
+ if (rep == m_u.table->entries()[entryIndex - 1].key) {
+ attributes = m_u.table->entries()[entryIndex - 1].attributes;
+ return m_u.table->entries()[entryIndex - 1].value;
+ }
+ }
+}
+
+JSValue* PropertyMap::get(const Identifier& name) const
+{
+ ASSERT(!name.isNull());
+
+ UString::Rep* rep = name._ustring.rep();
+
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ if (rep == m_singleEntryKey)
+ return m_u.singleEntryValue;
+#endif
+ return 0;
+ }
+
+ unsigned i = rep->computedHash();
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+#endif
+
+ unsigned entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ if (entryIndex == emptyEntryIndex)
+ return 0;
+
+ if (rep == m_u.table->entries()[entryIndex - 1].key)
+ return m_u.table->entries()[entryIndex - 1].value;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+
+ unsigned k = 1 | doubleHash(rep->computedHash());
+
+ while (1) {
+ i += k;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+
+ entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ if (entryIndex == emptyEntryIndex)
+ return 0;
+
+ if (rep == m_u.table->entries()[entryIndex - 1].key)
+ return m_u.table->entries()[entryIndex - 1].value;
+ }
+}
+
+JSValue** PropertyMap::getLocation(const Identifier& name)
+{
+ ASSERT(!name.isNull());
+
+ UString::Rep* rep = name._ustring.rep();
+
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ if (rep == m_singleEntryKey)
+ return &m_u.singleEntryValue;
+#endif
+ return 0;
+ }
+
+ unsigned i = rep->computedHash();
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+#endif
+
+ unsigned entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ if (entryIndex == emptyEntryIndex)
+ return 0;
+
+ if (rep == m_u.table->entries()[entryIndex - 1].key)
+ return &m_u.table->entries()[entryIndex - 1].value;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+
+ unsigned k = 1 | doubleHash(rep->computedHash());
+
+ while (1) {
+ i += k;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+
+ entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ if (entryIndex == emptyEntryIndex)
+ return 0;
+
+ if (rep == m_u.table->entries()[entryIndex - 1].key)
+ return &m_u.table->entries()[entryIndex - 1].value;
+ }
+}
+
+void PropertyMap::put(const Identifier& name, JSValue* value, unsigned attributes, bool checkReadOnly)
+{
+ ASSERT(!name.isNull());
+ ASSERT(value);
+
+ checkConsistency();
+
+ UString::Rep* rep = name._ustring.rep();
+
+#if USE_SINGLE_ENTRY
+ if (!m_usingTable) {
+ if (!m_singleEntryKey) {
+ rep->ref();
+ m_singleEntryKey = rep;
+ m_u.singleEntryValue = value;
+ m_singleEntryAttributes = static_cast<short>(attributes);
+ checkConsistency();
+ return;
+ }
+ if (rep == m_singleEntryKey && !(checkReadOnly && (m_singleEntryAttributes & ReadOnly))) {
+ m_u.singleEntryValue = value;
+ return;
+ }
+ }
+#endif
+
+ if (!m_usingTable || (m_u.table->keyCount + m_u.table->deletedSentinelCount) * 2 >= m_u.table->size)
+ expand();
+
+ // FIXME: Consider a fast case for tables with no deleted sentinels.
+
+ unsigned i = rep->computedHash();
+ unsigned k = 0;
+ bool foundDeletedElement = false;
+ unsigned deletedElementIndex = 0; // initialize to make the compiler happy
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+#endif
+
+ while (1) {
+ unsigned entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ if (entryIndex == emptyEntryIndex)
+ break;
+
+ if (m_u.table->entries()[entryIndex - 1].key == rep) {
+ if (checkReadOnly && (m_u.table->entries()[entryIndex - 1].attributes & ReadOnly))
+ return;
+ // Put a new value in an existing hash table entry.
+ m_u.table->entries()[entryIndex - 1].value = value;
+ // Attributes are intentionally not updated.
+ return;
+ } else if (entryIndex == deletedSentinelIndex) {
+ // If we find a deleted-element sentinel, remember it for use later.
+ if (!foundDeletedElement) {
+ foundDeletedElement = true;
+ deletedElementIndex = i;
+ }
+ }
+
+ if (k == 0) {
+ k = 1 | doubleHash(rep->computedHash());
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+ }
+
+ i += k;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+ }
+
+ // Figure out which entry to use.
+ unsigned entryIndex = m_u.table->keyCount + m_u.table->deletedSentinelCount + 2;
+ if (foundDeletedElement) {
+ i = deletedElementIndex;
+ --m_u.table->deletedSentinelCount;
+
+ // Since we're not making the table bigger, we can't use the entry one past
+ // the end that we were planning on using, so search backwards for the empty
+ // slot that we can use. We know it will be there because we did at least one
+ // deletion in the past that left an entry empty.
+ while (m_u.table->entries()[--entryIndex - 1].key)
+ ;
+ }
+
+
+ // Create a new hash table entry.
+ m_u.table->entryIndicies[i & m_u.table->sizeMask] = entryIndex;
+
+ // Create a new hash table entry.
+ rep->ref();
+ m_u.table->entries()[entryIndex - 1].key = rep;
+ m_u.table->entries()[entryIndex - 1].value = value;
+ m_u.table->entries()[entryIndex - 1].attributes = attributes;
+ m_u.table->entries()[entryIndex - 1].index = ++m_u.table->lastIndexUsed;
+ ++m_u.table->keyCount;
+
+ checkConsistency();
+}
+
+void PropertyMap::insert(const Entry& entry)
+{
+ ASSERT(m_u.table);
+
+ unsigned i = entry.key->computedHash();
+ unsigned k = 0;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+#endif
+
+ while (1) {
+ unsigned entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ if (entryIndex == emptyEntryIndex)
+ break;
+
+ if (k == 0) {
+ k = 1 | doubleHash(entry.key->computedHash());
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+ }
+
+ i += k;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+ }
+
+ unsigned entryIndex = m_u.table->keyCount + 2;
+ m_u.table->entryIndicies[i & m_u.table->sizeMask] = entryIndex;
+ m_u.table->entries()[entryIndex - 1] = entry;
+ ++m_u.table->keyCount;
+}
+
+void PropertyMap::expand()
+{
+ if (!m_usingTable)
+ createTable();
+ else
+ rehash(m_u.table->size * 2);
+}
+
+void PropertyMap::rehash()
+{
+ ASSERT(m_usingTable);
+ ASSERT(m_u.table);
+ ASSERT(m_u.table->size);
+ rehash(m_u.table->size);
+}
+
+void PropertyMap::createTable()
+{
+ const unsigned newTableSize = 16;
+
+ ASSERT(!m_usingTable);
+
+ checkConsistency();
+
+#if USE_SINGLE_ENTRY
+ JSValue* oldSingleEntryValue = m_u.singleEntryValue;
+#endif
+
+ m_u.table = static_cast<Table*>(fastZeroedMalloc(Table::allocationSize(newTableSize)));
+ m_u.table->size = newTableSize;
+ m_u.table->sizeMask = newTableSize - 1;
+ m_usingTable = true;
+
+#if USE_SINGLE_ENTRY
+ if (m_singleEntryKey) {
+ insert(Entry(m_singleEntryKey, oldSingleEntryValue, m_singleEntryAttributes));
+ m_singleEntryKey = 0;
+ }
+#endif
+
+ checkConsistency();
+}
+
+void PropertyMap::rehash(unsigned newTableSize)
+{
+ ASSERT(!m_singleEntryKey);
+ ASSERT(m_u.table);
+ ASSERT(m_usingTable);
+
+ checkConsistency();
+
+ Table* oldTable = m_u.table;
+
+ m_u.table = static_cast<Table*>(fastZeroedMalloc(Table::allocationSize(newTableSize)));
+ m_u.table->size = newTableSize;
+ m_u.table->sizeMask = newTableSize - 1;
+
+ unsigned lastIndexUsed = 0;
+ unsigned entryCount = oldTable->keyCount + oldTable->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; ++i) {
+ if (oldTable->entries()[i].key) {
+ lastIndexUsed = max(oldTable->entries()[i].index, lastIndexUsed);
+ insert(oldTable->entries()[i]);
+ }
+ }
+ m_u.table->lastIndexUsed = lastIndexUsed;
+
+ fastFree(oldTable);
+
+ checkConsistency();
+}
+
+void PropertyMap::remove(const Identifier& name)
+{
+ ASSERT(!name.isNull());
+
+ checkConsistency();
+
+ UString::Rep* rep = name._ustring.rep();
+
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ if (rep == m_singleEntryKey) {
+ m_singleEntryKey->deref();
+ m_singleEntryKey = 0;
+ checkConsistency();
+ }
+#endif
+ return;
+ }
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numProbes;
+ ++numRemoves;
+#endif
+
+ // Find the thing to remove.
+ unsigned i = rep->computedHash();
+ unsigned k = 0;
+ unsigned entryIndex;
+ UString::Rep* key = 0;
+ while (1) {
+ entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ if (entryIndex == emptyEntryIndex)
+ return;
+
+ key = m_u.table->entries()[entryIndex - 1].key;
+ if (rep == key)
+ break;
+
+ if (k == 0) {
+ k = 1 | doubleHash(rep->computedHash());
+#if DUMP_PROPERTYMAP_STATS
+ ++numCollisions;
+#endif
+ }
+
+ i += k;
+
+#if DUMP_PROPERTYMAP_STATS
+ ++numRehashes;
+#endif
+ }
+
+ // Replace this one element with the deleted sentinel. Also clear out
+ // the entry so we can iterate all the entries as needed.
+ m_u.table->entryIndicies[i & m_u.table->sizeMask] = deletedSentinelIndex;
+ key->deref();
+ m_u.table->entries()[entryIndex - 1].key = 0;
+ m_u.table->entries()[entryIndex - 1].value = jsUndefined();
+ m_u.table->entries()[entryIndex - 1].attributes = 0;
+ ASSERT(m_u.table->keyCount >= 1);
+ --m_u.table->keyCount;
+ ++m_u.table->deletedSentinelCount;
+
+ if (m_u.table->deletedSentinelCount * 4 >= m_u.table->size)
+ rehash();
+
+ checkConsistency();
+}
+
+void PropertyMap::mark() const
+{
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ if (m_singleEntryKey) {
+ JSValue* v = m_u.singleEntryValue;
+ if (!v->marked())
+ v->mark();
+ }
+#endif
+ return;
+ }
+
+ unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; i++) {
+ JSValue* v = m_u.table->entries()[i].value;
+ if (!v->marked())
+ v->mark();
+ }
+}
+
+static int comparePropertyMapEntryIndices(const void* a, const void* b)
+{
+ unsigned ia = static_cast<PropertyMapEntry* const*>(a)[0]->index;
+ unsigned ib = static_cast<PropertyMapEntry* const*>(b)[0]->index;
+ if (ia < ib)
+ return -1;
+ if (ia > ib)
+ return +1;
+ return 0;
+}
+
+bool PropertyMap::containsGettersOrSetters() const
+{
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ return !!(m_singleEntryAttributes & GetterSetter);
+#else
+ return false;
+#endif
+ }
+
+ unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; i++) {
+ if (m_u.table->entries()[i].attributes & GetterSetter)
+ return true;
+ }
+
+ return false;
+}
+
+void PropertyMap::getEnumerablePropertyNames(PropertyNameArray& propertyNames) const
+{
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ UString::Rep* key = m_singleEntryKey;
+ if (key && !(m_singleEntryAttributes & DontEnum))
+ propertyNames.add(Identifier(key));
+#endif
+ return;
+ }
+
+ if (m_u.table->keyCount < tinyMapThreshold) {
+ Entry* a[tinyMapThreshold];
+ int i = 0;
+ unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
+ for (unsigned k = 1; k <= entryCount; k++) {
+ if (m_u.table->entries()[k].key && !(m_u.table->entries()[k].attributes & DontEnum)) {
+ Entry* value = &m_u.table->entries()[k];
+ int j;
+ for (j = i - 1; j >= 0 && a[j]->index > value->index; --j)
+ a[j + 1] = a[j];
+ a[j + 1] = value;
+ ++i;
+ }
+ }
+ for (int k = 0; k < i; ++k)
+ propertyNames.add(Identifier(a[k]->key));
+ return;
+ }
+
+ // Allocate a buffer to use to sort the keys.
+ Vector<Entry*, smallMapThreshold> sortedEnumerables(m_u.table->keyCount);
+
+ // Get pointers to the enumerable entries in the buffer.
+ Entry** p = sortedEnumerables.data();
+ unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; i++) {
+ if (m_u.table->entries()[i].key && !(m_u.table->entries()[i].attributes & DontEnum))
+ *p++ = &m_u.table->entries()[i];
+ }
+
+ // Sort the entries by index.
+ qsort(sortedEnumerables.data(), p - sortedEnumerables.data(), sizeof(Entry*), comparePropertyMapEntryIndices);
+
+ // Put the keys of the sorted entries into the list.
+ for (Entry** q = sortedEnumerables.data(); q != p; ++q)
+ propertyNames.add(Identifier(q[0]->key));
+}
+
+void PropertyMap::save(SavedProperties& s) const
+{
+ unsigned count = 0;
+
+ if (!m_usingTable) {
+#if USE_SINGLE_ENTRY
+ if (m_singleEntryKey && !(m_singleEntryAttributes & (ReadOnly | Function)))
+ ++count;
+#endif
+ } else {
+ unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; ++i)
+ if (m_u.table->entries()[i].key && !(m_u.table->entries()[i].attributes & (ReadOnly | Function)))
+ ++count;
+ }
+
+ s.properties.clear();
+ s.count = count;
+
+ if (count == 0)
+ return;
+
+ s.properties.set(new SavedProperty[count]);
+
+ SavedProperty* prop = s.properties.get();
+
+#if USE_SINGLE_ENTRY
+ if (!m_usingTable) {
+ prop->init(m_singleEntryKey, m_u.singleEntryValue, m_singleEntryAttributes);
+ return;
+ }
+#endif
+
+ // Save in the right order so we don't lose the order.
+ // Another possibility would be to save the indices.
+
+ // Allocate a buffer to use to sort the keys.
+ Vector<Entry*, smallMapThreshold> sortedEntries(count);
+
+ // Get pointers to the entries in the buffer.
+ Entry** p = sortedEntries.data();
+ unsigned entryCount = m_u.table->keyCount + m_u.table->deletedSentinelCount;
+ for (unsigned i = 1; i <= entryCount; ++i) {
+ if (m_u.table->entries()[i].key && !(m_u.table->entries()[i].attributes & (ReadOnly | Function)))
+ *p++ = &m_u.table->entries()[i];
+ }
+ ASSERT(p == sortedEntries.data() + count);
+
+ // Sort the entries by index.
+ qsort(sortedEntries.data(), p - sortedEntries.data(), sizeof(Entry*), comparePropertyMapEntryIndices);
+
+ // Put the sorted entries into the saved properties list.
+ for (Entry** q = sortedEntries.data(); q != p; ++q, ++prop) {
+ Entry* e = *q;
+ prop->init(e->key, e->value, e->attributes);
+ }
+}
+
+void PropertyMap::restore(const SavedProperties& p)
+{
+ for (unsigned i = 0; i != p.count; ++i)
+ put(Identifier(p.properties[i].name()), p.properties[i].value(), p.properties[i].attributes());
+}
+
+#if DO_PROPERTYMAP_CONSTENCY_CHECK
+
+void PropertyMap::checkConsistency()
+{
+ if (!m_usingTable)
+ return;
+
+ ASSERT(m_u.table->size >= 16);
+ ASSERT(m_u.table->sizeMask);
+ ASSERT(m_u.table->size == m_u.table->sizeMask + 1);
+ ASSERT(!(m_u.table->size & m_u.table->sizeMask));
+
+ ASSERT(m_u.table->keyCount <= m_u.table->size / 2);
+ ASSERT(m_u.table->deletedSentinelCount <= m_u.table->size / 4);
+
+ ASSERT(m_u.table->keyCount + m_u.table->deletedSentinelCount <= m_u.table->size / 2);
+
+ unsigned indexCount = 0;
+ unsigned deletedIndexCount = 0;
+ for (unsigned a = 0; a != m_u.table->size; ++a) {
+ unsigned entryIndex = m_u.table->entryIndicies[a];
+ if (entryIndex == emptyEntryIndex)
+ continue;
+ if (entryIndex == deletedSentinelIndex) {
+ ++deletedIndexCount;
+ continue;
+ }
+ ASSERT(entryIndex > deletedSentinelIndex);
+ ASSERT(entryIndex - 1 <= m_u.table->keyCount + m_u.table->deletedSentinelCount);
+ ++indexCount;
+
+ for (unsigned b = a + 1; b != m_u.table->size; ++b)
+ ASSERT(m_u.table->entryIndicies[b] != entryIndex);
+ }
+ ASSERT(indexCount == m_u.table->keyCount);
+ ASSERT(deletedIndexCount == m_u.table->deletedSentinelCount);
+
+ ASSERT(m_u.table->entries()[0].key == 0);
+
+ unsigned nonEmptyEntryCount = 0;
+ for (unsigned c = 1; c <= m_u.table->keyCount + m_u.table->deletedSentinelCount; ++c) {
+ UString::Rep* rep = m_u.table->entries()[c].key;
+ if (!rep) {
+ ASSERT(m_u.table->entries()[c].value->isUndefined());
+ continue;
+ }
+ ++nonEmptyEntryCount;
+ unsigned i = rep->computedHash();
+ unsigned k = 0;
+ unsigned entryIndex;
+ while (1) {
+ entryIndex = m_u.table->entryIndicies[i & m_u.table->sizeMask];
+ ASSERT(entryIndex != emptyEntryIndex);
+ if (rep == m_u.table->entries()[entryIndex - 1].key)
+ break;
+ if (k == 0)
+ k = 1 | doubleHash(rep->computedHash());
+ i += k;
+ }
+ ASSERT(entryIndex == c + 1);
+ }
+
+ ASSERT(nonEmptyEntryCount == m_u.table->keyCount);
+}
+
+#endif // DO_PROPERTYMAP_CONSTENCY_CHECK
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/property_map.h b/JavaScriptCore/kjs/property_map.h
new file mode 100644
index 0000000..269e911
--- /dev/null
+++ b/JavaScriptCore/kjs/property_map.h
@@ -0,0 +1,184 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * 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 KJS_PROPERTY_MAP_H_
+#define KJS_PROPERTY_MAP_H_
+
+#include "identifier.h"
+#include "protect.h"
+#include <wtf/OwnArrayPtr.h>
+
+namespace KJS {
+
+ class JSObject;
+ class JSValue;
+ class PropertyNameArray;
+
+ struct PropertyMapEntry;
+ struct PropertyMapHashTable;
+
+ class SavedProperty : Noncopyable {
+ public:
+ // Since we use this in arrays, we allocate it uninitialized
+ // and then explicitly initialize. This means we can allocate
+ // the array without initializing every saved property in the
+ // array twice. To accomplish this, the class uses data members
+ // with types that don't have constructors.
+ SavedProperty();
+ void init(UString::Rep* name, JSValue*, unsigned attributes);
+ ~SavedProperty();
+
+ UString::Rep* name() const;
+ JSValue* value() const;
+ unsigned attributes() const;
+
+ private:
+ UString::Rep* m_name;
+ JSValue* m_value;
+ unsigned m_attributes;
+ };
+
+ struct SavedProperties {
+ SavedProperties();
+ ~SavedProperties();
+
+ unsigned count;
+ OwnArrayPtr<SavedProperty> properties;
+ };
+
+ class PropertyMap : Noncopyable {
+ public:
+ PropertyMap();
+ ~PropertyMap();
+
+ void clear();
+
+ void put(const Identifier&, JSValue*, unsigned attributes, bool checkReadOnly = false);
+ void remove(const Identifier&);
+ JSValue* get(const Identifier&) const;
+ JSValue* get(const Identifier&, unsigned& attributes) const;
+ JSValue** getLocation(const Identifier& name);
+
+ void mark() const;
+ void getEnumerablePropertyNames(PropertyNameArray&) const;
+
+ void save(SavedProperties&) const;
+ void restore(const SavedProperties&);
+
+ bool hasGetterSetterProperties() const { return m_getterSetterFlag; }
+ void setHasGetterSetterProperties(bool f) { m_getterSetterFlag = f; }
+
+ bool containsGettersOrSetters() const;
+
+ private:
+ typedef PropertyMapEntry Entry;
+ typedef PropertyMapHashTable Table;
+
+ static bool keysMatch(const UString::Rep*, const UString::Rep*);
+ void expand();
+ void rehash();
+ void rehash(unsigned newTableSize);
+ void createTable();
+
+ void insert(const Entry&);
+
+ void checkConsistency();
+
+ UString::Rep* m_singleEntryKey;
+ union {
+ JSValue* singleEntryValue;
+ Table* table;
+ } m_u;
+
+ short m_singleEntryAttributes;
+ bool m_getterSetterFlag : 1;
+ bool m_usingTable : 1;
+ };
+
+ inline PropertyMap::PropertyMap()
+ : m_singleEntryKey(0)
+ , m_getterSetterFlag(false)
+ , m_usingTable(false)
+
+ {
+ }
+
+ inline SavedProperty::SavedProperty()
+#ifndef NDEBUG
+ : m_name(0)
+ , m_value(0)
+ , m_attributes(0)
+#endif
+ {
+ }
+
+ inline void SavedProperty::init(UString::Rep* name, JSValue* value, unsigned attributes)
+ {
+ ASSERT(name);
+ ASSERT(value);
+
+ ASSERT(!m_name);
+ ASSERT(!m_value);
+ ASSERT(!m_attributes);
+
+ m_name = name;
+ m_value = value;
+ m_attributes = attributes;
+ name->ref();
+ gcProtect(value);
+ }
+
+ inline SavedProperty::~SavedProperty()
+ {
+ ASSERT(m_name);
+ ASSERT(m_value);
+
+ m_name->deref();
+ gcUnprotect(m_value);
+ }
+
+ inline UString::Rep* SavedProperty::name() const
+ {
+ ASSERT(m_name);
+ ASSERT(m_value);
+
+ return m_name;
+ }
+
+ inline JSValue* SavedProperty::value() const
+ {
+ ASSERT(m_name);
+ ASSERT(m_value);
+
+ return m_value;
+ }
+
+ inline unsigned SavedProperty::attributes() const
+ {
+ ASSERT(m_name);
+ ASSERT(m_value);
+
+ return m_attributes;
+ }
+
+} // namespace
+
+#endif // _KJS_PROPERTY_MAP_H_
diff --git a/JavaScriptCore/kjs/property_slot.cpp b/JavaScriptCore/kjs/property_slot.cpp
new file mode 100644
index 0000000..ef2525f
--- /dev/null
+++ b/JavaScriptCore/kjs/property_slot.cpp
@@ -0,0 +1,46 @@
+// -*- c-basic-offset: 4 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2005 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#include "config.h"
+#include "property_slot.h"
+#include "object.h"
+
+namespace KJS {
+
+JSValue *PropertySlot::undefinedGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&)
+{
+ return jsUndefined();
+}
+
+JSValue* PropertySlot::ungettableGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&)
+{
+ ASSERT_NOT_REACHED();
+ return jsUndefined();
+}
+
+JSValue *PropertySlot::functionGetter(ExecState* exec, JSObject* originalObject, const Identifier&, const PropertySlot& slot)
+{
+ return slot.m_data.getterFunc->call(exec, originalObject, exec->emptyList());
+}
+
+}
diff --git a/JavaScriptCore/kjs/property_slot.h b/JavaScriptCore/kjs/property_slot.h
new file mode 100644
index 0000000..4ec8b46
--- /dev/null
+++ b/JavaScriptCore/kjs/property_slot.h
@@ -0,0 +1,142 @@
+// -*- c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2005, 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 KJS_PROPERTY_SLOT_H
+#define KJS_PROPERTY_SLOT_H
+
+#include "identifier.h"
+#include "value.h"
+#include <wtf/Assertions.h>
+
+namespace KJS {
+
+class ExecState;
+class JSObject;
+
+struct HashEntry;
+
+#define KJS_VALUE_SLOT_MARKER 0
+#define KJS_NUMERIC_PROPERTY_NAME_SLOT_MARKER reinterpret_cast<GetValueFunc>(1)
+
+class PropertySlot {
+public:
+ typedef JSValue* (*GetValueFunc)(ExecState*, JSObject* originalObject, const Identifier&, const PropertySlot&);
+ typedef JSValue* (*GetValueNumericFunc)(ExecState*, JSObject* originalObject, unsigned index, const PropertySlot&);
+
+ JSValue* getValue(ExecState* exec, JSObject* originalObject, const Identifier& propertyName) const
+ {
+ if (m_getValue == KJS_VALUE_SLOT_MARKER)
+ return *m_data.valueSlot;
+ ASSERT(m_getValue != KJS_NUMERIC_PROPERTY_NAME_SLOT_MARKER);
+ return m_getValue(exec, originalObject, propertyName, *this);
+ }
+
+ JSValue* getValue(ExecState* exec, JSObject* originalObject, unsigned propertyName) const
+ {
+ if (m_getValue == KJS_VALUE_SLOT_MARKER)
+ return *m_data.valueSlot;
+ if (m_getValue == KJS_NUMERIC_PROPERTY_NAME_SLOT_MARKER)
+ return m_data.numericFunc(exec, originalObject, propertyName, *this);
+ return m_getValue(exec, originalObject, Identifier::from(propertyName), *this);
+ }
+
+ void setValueSlot(JSObject* slotBase, JSValue** valueSlot)
+ {
+ m_getValue = KJS_VALUE_SLOT_MARKER;
+ m_slotBase = slotBase;
+ m_data.valueSlot = valueSlot;
+ }
+
+ void setStaticEntry(JSObject* slotBase, const HashEntry* staticEntry, GetValueFunc getValue)
+ {
+ ASSERT(getValue);
+ m_getValue = getValue;
+ m_slotBase = slotBase;
+ m_data.staticEntry = staticEntry;
+ }
+
+ void setCustom(JSObject* slotBase, GetValueFunc getValue)
+ {
+ ASSERT(getValue);
+ m_getValue = getValue;
+ m_slotBase = slotBase;
+ }
+
+ void setCustomIndex(JSObject* slotBase, unsigned index, GetValueFunc getValue)
+ {
+ ASSERT(getValue);
+ m_getValue = getValue;
+ m_slotBase = slotBase;
+ m_data.index = index;
+ }
+
+ void setCustomNumeric(JSObject* slotBase, GetValueNumericFunc getValue)
+ {
+ ASSERT(getValue);
+ m_slotBase = slotBase;
+ m_getValue = KJS_NUMERIC_PROPERTY_NAME_SLOT_MARKER;
+ m_data.numericFunc = getValue;
+ }
+
+ void setGetterSlot(JSObject* slotBase, JSObject* getterFunc)
+ {
+ m_getValue = functionGetter;
+ m_slotBase = slotBase;
+ m_data.getterFunc = getterFunc;
+ }
+
+ void setUndefined(JSObject *slotBase)
+ {
+ m_slotBase = slotBase;
+ m_getValue = undefinedGetter;
+ }
+
+ void setUngettable(JSObject* slotBase) // Used to signal that you have a property, but trying to get it at this time is an error.
+ {
+ m_slotBase = slotBase;
+ m_getValue = ungettableGetter;
+ }
+
+ JSObject* slotBase() const { return m_slotBase; }
+
+ const HashEntry* staticEntry() const { return m_data.staticEntry; }
+ unsigned index() const { return m_data.index; }
+
+private:
+ static JSValue* undefinedGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
+ static JSValue* ungettableGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
+ static JSValue* functionGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot&);
+
+ GetValueFunc m_getValue;
+
+ JSObject* m_slotBase;
+ union {
+ JSObject* getterFunc;
+ JSValue** valueSlot;
+ const HashEntry* staticEntry;
+ unsigned index;
+ GetValueNumericFunc numericFunc;
+ } m_data;
+};
+
+}
+
+#endif // KJS_PROPERTY_SLOT_H
diff --git a/JavaScriptCore/kjs/protect.h b/JavaScriptCore/kjs/protect.h
new file mode 100644
index 0000000..912e45c
--- /dev/null
+++ b/JavaScriptCore/kjs/protect.h
@@ -0,0 +1,143 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2004 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+
+#ifndef _KJS_PROTECT_H_
+#define _KJS_PROTECT_H_
+
+#include "value.h"
+#include "collector.h"
+#include "JSLock.h"
+
+namespace KJS {
+
+ inline void gcProtect(JSValue *val)
+ {
+ Collector::protect(val);
+ }
+
+ inline void gcUnprotect(JSValue *val)
+ {
+ Collector::unprotect(val);
+ }
+
+ inline void gcProtectNullTolerant(JSValue *val)
+ {
+ if (val)
+ gcProtect(val);
+ }
+
+ inline void gcUnprotectNullTolerant(JSValue *val)
+ {
+ if (val)
+ gcUnprotect(val);
+ }
+
+ // FIXME: Share more code with RefPtr template? The only differences are the ref/deref operation
+ // and the implicit conversion to raw pointer
+ template <class T> class ProtectedPtr {
+ public:
+ ProtectedPtr() : m_ptr(NULL) { }
+ ProtectedPtr(T *ptr);
+ ProtectedPtr(const ProtectedPtr &);
+ ~ProtectedPtr();
+
+ template <class U> ProtectedPtr(const ProtectedPtr<U> &);
+
+ T *get() const { return m_ptr; }
+ operator T *() const { return m_ptr; }
+ T *operator->() const { return m_ptr; }
+
+ bool operator!() const { return m_ptr == NULL; }
+
+ ProtectedPtr &operator=(const ProtectedPtr &);
+ ProtectedPtr &operator=(T *);
+
+ private:
+ T *m_ptr;
+ };
+
+ template <class T> ProtectedPtr<T>::ProtectedPtr(T *ptr)
+ : m_ptr(ptr)
+ {
+ if (ptr) {
+ JSLock lock;
+ gcProtect(ptr);
+ }
+ }
+
+ template <class T> ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr &o)
+ : m_ptr(o.get())
+ {
+ if (T *ptr = m_ptr) {
+ JSLock lock;
+ gcProtect(ptr);
+ }
+ }
+
+ template <class T> ProtectedPtr<T>::~ProtectedPtr()
+ {
+ if (T *ptr = m_ptr) {
+ JSLock lock;
+ gcUnprotect(ptr);
+ }
+ }
+
+ template <class T> template <class U> ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr<U> &o)
+ : m_ptr(o.get())
+ {
+ if (T *ptr = m_ptr) {
+ JSLock lock;
+ gcProtect(ptr);
+ }
+ }
+
+ template <class T> ProtectedPtr<T> &ProtectedPtr<T>::operator=(const ProtectedPtr<T> &o)
+ {
+ JSLock lock;
+ T *optr = o.m_ptr;
+ gcProtectNullTolerant(optr);
+ gcUnprotectNullTolerant(m_ptr);
+ m_ptr = optr;
+ return *this;
+ }
+
+ template <class T> inline ProtectedPtr<T> &ProtectedPtr<T>::operator=(T *optr)
+ {
+ JSLock lock;
+ gcProtectNullTolerant(optr);
+ gcUnprotectNullTolerant(m_ptr);
+ m_ptr = optr;
+ return *this;
+ }
+
+ template <class T> inline bool operator==(const ProtectedPtr<T> &a, const ProtectedPtr<T> &b) { return a.get() == b.get(); }
+ template <class T> inline bool operator==(const ProtectedPtr<T> &a, const T *b) { return a.get() == b; }
+ template <class T> inline bool operator==(const T *a, const ProtectedPtr<T> &b) { return a == b.get(); }
+
+ template <class T> inline bool operator!=(const ProtectedPtr<T> &a, const ProtectedPtr<T> &b) { return a.get() != b.get(); }
+ template <class T> inline bool operator!=(const ProtectedPtr<T> &a, const T *b) { return a.get() != b; }
+ template <class T> inline bool operator!=(const T *a, const ProtectedPtr<T> &b) { return a != b.get(); }
+
+} // namespace
+
+#endif
diff --git a/JavaScriptCore/kjs/regexp.cpp b/JavaScriptCore/kjs/regexp.cpp
new file mode 100644
index 0000000..4fbc645
--- /dev/null
+++ b/JavaScriptCore/kjs/regexp.cpp
@@ -0,0 +1,131 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 1999-2001, 2004 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 "regexp.h"
+
+#include "lexer.h"
+#include <pcre/pcre.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wtf/Assertions.h>
+#include <wtf/OwnArrayPtr.h>
+
+namespace KJS {
+
+inline RegExp::RegExp(const UString& pattern)
+ : m_pattern(pattern)
+ , m_flagBits(0)
+ , m_constructionError(0)
+ , m_numSubpatterns(0)
+{
+ m_regExp = jsRegExpCompile(reinterpret_cast<const ::UChar*>(pattern.data()), pattern.size(),
+ JSRegExpDoNotIgnoreCase, JSRegExpSingleLine, &m_numSubpatterns, &m_constructionError);
+}
+
+PassRefPtr<RegExp> RegExp::create(const UString& pattern)
+{
+ return adoptRef(new RegExp(pattern));
+}
+
+inline RegExp::RegExp(const UString& pattern, const UString& flags)
+ : m_pattern(pattern)
+ , m_flags(flags)
+ , m_flagBits(0)
+ , m_constructionError(0)
+ , m_numSubpatterns(0)
+{
+ // NOTE: The global flag is handled on a case-by-case basis by functions like
+ // String::match and RegExpImp::match.
+ if (flags.find('g') != -1)
+ m_flagBits |= Global;
+
+ // FIXME: Eliminate duplication by adding a way ask a JSRegExp what its flags are?
+ JSRegExpIgnoreCaseOption ignoreCaseOption = JSRegExpDoNotIgnoreCase;
+ if (flags.find('i') != -1) {
+ m_flagBits |= IgnoreCase;
+ ignoreCaseOption = JSRegExpIgnoreCase;
+ }
+
+ JSRegExpMultilineOption multilineOption = JSRegExpSingleLine;
+ if (flags.find('m') != -1) {
+ m_flagBits |= Multiline;
+ multilineOption = JSRegExpMultiline;
+ }
+
+ m_regExp = jsRegExpCompile(reinterpret_cast<const ::UChar*>(pattern.data()), pattern.size(),
+ ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError);
+}
+
+PassRefPtr<RegExp> RegExp::create(const UString& pattern, const UString& flags)
+{
+ return adoptRef(new RegExp(pattern, flags));
+}
+
+RegExp::~RegExp()
+{
+ jsRegExpFree(m_regExp);
+}
+
+int RegExp::match(const UString& s, int i, OwnArrayPtr<int>* ovector)
+{
+ if (i < 0)
+ i = 0;
+ if (ovector)
+ ovector->clear();
+
+ if (i > s.size() || s.isNull())
+ return -1;
+
+ if (!m_regExp)
+ return -1;
+
+ // Set up the offset vector for the result.
+ // First 2/3 used for result, the last third used by PCRE.
+ int* offsetVector;
+ int offsetVectorSize;
+ int fixedSizeOffsetVector[3];
+ if (!ovector) {
+ offsetVectorSize = 3;
+ offsetVector = fixedSizeOffsetVector;
+ } else {
+ offsetVectorSize = (m_numSubpatterns + 1) * 3;
+ offsetVector = new int [offsetVectorSize];
+ ovector->set(offsetVector);
+ }
+
+ int numMatches = jsRegExpExecute(m_regExp, reinterpret_cast<const ::UChar*>(s.data()), s.size(), i, offsetVector, offsetVectorSize);
+
+ if (numMatches < 0) {
+#ifndef NDEBUG
+ if (numMatches != JSRegExpErrorNoMatch)
+ fprintf(stderr, "jsRegExpExecute failed with result %d\n", numMatches);
+#endif
+ if (ovector)
+ ovector->clear();
+ return -1;
+ }
+
+ return offsetVector[0];
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/regexp.h b/JavaScriptCore/kjs/regexp.h
new file mode 100644
index 0000000..1930ac9
--- /dev/null
+++ b/JavaScriptCore/kjs/regexp.h
@@ -0,0 +1,69 @@
+/*
+ * 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 KJS_REGEXP_H
+#define KJS_REGEXP_H
+
+#include "ustring.h"
+#include <wtf/Forward.h>
+#include <wtf/RefCounted.h>
+
+struct JSRegExp;
+
+namespace KJS {
+
+ class RegExp : public RefCounted<RegExp> {
+ public:
+ static PassRefPtr<RegExp> create(const UString& pattern);
+ static PassRefPtr<RegExp> create(const UString& pattern, const UString& flags);
+ ~RegExp();
+
+ bool global() const { return m_flagBits & Global; }
+ bool ignoreCase() const { return m_flagBits & IgnoreCase; }
+ bool multiline() const { return m_flagBits & Multiline; }
+
+ const UString& pattern() const { return m_pattern; }
+ const UString& flags() const { return m_flags; }
+
+ bool isValid() const { return !m_constructionError; }
+ const char* errorMessage() const { return m_constructionError; }
+
+ int match(const UString&, int offset, OwnArrayPtr<int>* ovector = 0);
+ unsigned numSubpatterns() const { return m_numSubpatterns; }
+
+ private:
+ RegExp(const UString& pattern);
+ RegExp(const UString& pattern, const UString& flags);
+
+ void compile();
+
+ enum FlagBits { Global = 1, IgnoreCase = 2, Multiline = 4 };
+
+ UString m_pattern; // FIXME: Just decompile m_regExp instead of storing this.
+ UString m_flags; // FIXME: Just decompile m_regExp instead of storing this.
+ int m_flagBits;
+ JSRegExp* m_regExp;
+ const char* m_constructionError;
+ unsigned m_numSubpatterns;
+ };
+
+} // namespace
+
+#endif
diff --git a/JavaScriptCore/kjs/regexp_object.cpp b/JavaScriptCore/kjs/regexp_object.cpp
new file mode 100644
index 0000000..871d764
--- /dev/null
+++ b/JavaScriptCore/kjs/regexp_object.cpp
@@ -0,0 +1,475 @@
+/*
+ * 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 "regexp_object.h"
+#include "regexp_object.lut.h"
+
+#include "array_instance.h"
+#include "array_object.h"
+#include "error_object.h"
+#include "internal.h"
+#include "object.h"
+#include "operations.h"
+#include "regexp.h"
+#include "types.h"
+#include "value.h"
+#include "UnusedParam.h"
+
+#include <stdio.h>
+
+namespace KJS {
+
+// ------------------------------ RegExpPrototype ---------------------------
+
+static JSValue* regExpProtoFuncTest(ExecState*, JSObject*, const List&);
+static JSValue* regExpProtoFuncExec(ExecState*, JSObject*, const List&);
+static JSValue* regExpProtoFuncCompile(ExecState*, JSObject*, const List&);
+static JSValue* regExpProtoFuncToString(ExecState*, JSObject*, const List&);
+
+// ECMA 15.10.5
+
+const ClassInfo RegExpPrototype::info = { "RegExpPrototype", 0, 0 };
+
+RegExpPrototype::RegExpPrototype(ExecState* exec, ObjectPrototype* objectPrototype, FunctionPrototype* functionPrototype)
+ : JSObject(objectPrototype)
+{
+ static const Identifier* compilePropertyName = new Identifier("compile");
+ static const Identifier* execPropertyName = new Identifier("exec");
+ static const Identifier* testPropertyName = new Identifier("test");
+
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, *compilePropertyName, regExpProtoFuncCompile), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, *execPropertyName, regExpProtoFuncExec), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, *testPropertyName, regExpProtoFuncTest), DontEnum);
+ putDirectFunction(new PrototypeFunction(exec, functionPrototype, 0, exec->propertyNames().toString, regExpProtoFuncToString), DontEnum);
+}
+
+// ------------------------------ Functions ---------------------------
+
+JSValue* regExpProtoFuncTest(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&RegExpImp::info))
+ return throwError(exec, TypeError);
+
+ return static_cast<RegExpImp*>(thisObj)->test(exec, args);
+}
+
+JSValue* regExpProtoFuncExec(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&RegExpImp::info))
+ return throwError(exec, TypeError);
+
+ return static_cast<RegExpImp*>(thisObj)->exec(exec, args);
+}
+
+JSValue* regExpProtoFuncCompile(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (!thisObj->inherits(&RegExpImp::info))
+ return throwError(exec, TypeError);
+
+ RefPtr<RegExp> regExp;
+ JSValue* arg0 = args[0];
+ JSValue* arg1 = args[1];
+
+ if (arg0->isObject(&RegExpImp::info)) {
+ if (!arg1->isUndefined())
+ return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
+ regExp = static_cast<RegExpImp*>(arg0)->regExp();
+ } else {
+ UString pattern = args.isEmpty() ? UString("") : arg0->toString(exec);
+ UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
+ regExp = RegExp::create(pattern, flags);
+ }
+
+ if (!regExp->isValid())
+ return throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
+
+ static_cast<RegExpImp*>(thisObj)->setRegExp(regExp.release());
+ static_cast<RegExpImp*>(thisObj)->setLastIndex(0);
+ return jsUndefined();
+}
+
+JSValue* regExpProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&RegExpImp::info)) {
+ if (thisObj->inherits(&RegExpPrototype::info))
+ return jsString("//");
+ return throwError(exec, TypeError);
+ }
+
+ UString result = "/" + thisObj->get(exec, exec->propertyNames().source)->toString(exec) + "/";
+ if (thisObj->get(exec, exec->propertyNames().global)->toBoolean(exec))
+ result += "g";
+ if (thisObj->get(exec, exec->propertyNames().ignoreCase)->toBoolean(exec))
+ result += "i";
+ if (thisObj->get(exec, exec->propertyNames().multiline)->toBoolean(exec))
+ result += "m";
+ return jsString(result);
+}
+
+// ------------------------------ RegExpImp ------------------------------------
+
+const ClassInfo RegExpImp::info = { "RegExp", 0, &RegExpImpTable };
+
+/* Source for regexp_object.lut.h
+@begin RegExpImpTable 5
+ global RegExpImp::Global DontDelete|ReadOnly|DontEnum
+ ignoreCase RegExpImp::IgnoreCase DontDelete|ReadOnly|DontEnum
+ multiline RegExpImp::Multiline DontDelete|ReadOnly|DontEnum
+ source RegExpImp::Source DontDelete|ReadOnly|DontEnum
+ lastIndex RegExpImp::LastIndex DontDelete|DontEnum
+@end
+*/
+
+RegExpImp::RegExpImp(RegExpPrototype* regexpProto, PassRefPtr<RegExp> regExp)
+ : JSObject(regexpProto)
+ , m_regExp(regExp)
+ , m_lastIndex(0)
+{
+}
+
+RegExpImp::~RegExpImp()
+{
+}
+
+bool RegExpImp::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticValueSlot<RegExpImp, JSObject>(exec, &RegExpImpTable, this, propertyName, slot);
+}
+
+JSValue* RegExpImp::getValueProperty(ExecState*, int token) const
+{
+ switch (token) {
+ case Global:
+ return jsBoolean(m_regExp->global());
+ case IgnoreCase:
+ return jsBoolean(m_regExp->ignoreCase());
+ case Multiline:
+ return jsBoolean(m_regExp->multiline());
+ case Source:
+ return jsString(m_regExp->pattern());
+ case LastIndex:
+ return jsNumber(m_lastIndex);
+ }
+
+ ASSERT_NOT_REACHED();
+ return 0;
+}
+
+void RegExpImp::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
+{
+ lookupPut<RegExpImp, JSObject>(exec, propertyName, value, &RegExpImpTable, this);
+}
+
+void RegExpImp::putValueProperty(ExecState* exec, int token, JSValue* value)
+{
+ UNUSED_PARAM(token);
+ ASSERT(token == LastIndex);
+ m_lastIndex = value->toInteger(exec);
+}
+
+bool RegExpImp::match(ExecState* exec, const List& args)
+{
+ RegExpObjectImp* regExpObj = exec->lexicalGlobalObject()->regExpConstructor();
+
+ UString input;
+ if (!args.isEmpty())
+ input = args[0]->toString(exec);
+ else {
+ input = regExpObj->input();
+ if (input.isNull()) {
+ throwError(exec, GeneralError, "No input.");
+ return false;
+ }
+ }
+
+ bool global = get(exec, exec->propertyNames().global)->toBoolean(exec);
+ int lastIndex = 0;
+ if (global) {
+ if (m_lastIndex < 0 || m_lastIndex > input.size()) {
+ m_lastIndex = 0;
+ return false;
+ }
+ lastIndex = static_cast<int>(m_lastIndex);
+ }
+
+ int foundIndex;
+ int foundLength;
+ regExpObj->performMatch(m_regExp.get(), input, lastIndex, foundIndex, foundLength);
+
+ if (global) {
+ lastIndex = foundIndex < 0 ? 0 : foundIndex + foundLength;
+ m_lastIndex = lastIndex;
+ }
+
+ return foundIndex >= 0;
+}
+
+JSValue* RegExpImp::test(ExecState* exec, const List& args)
+{
+ return jsBoolean(match(exec, args));
+}
+
+JSValue* RegExpImp::exec(ExecState* exec, const List& args)
+{
+ return match(exec, args)
+ ? exec->lexicalGlobalObject()->regExpConstructor()->arrayOfMatches(exec)
+ : jsNull();
+}
+
+bool RegExpImp::implementsCall() const
+{
+ return true;
+}
+
+JSValue* RegExpImp::callAsFunction(ExecState* exec, JSObject*, const List& args)
+{
+ return RegExpImp::exec(exec, args);
+}
+
+// ------------------------------ RegExpObjectImp ------------------------------
+
+const ClassInfo RegExpObjectImp::info = { "Function", &InternalFunctionImp::info, &RegExpObjectImpTable };
+
+/* Source for regexp_object.lut.h
+@begin RegExpObjectImpTable 21
+ input RegExpObjectImp::Input None
+ $_ RegExpObjectImp::Input DontEnum
+ multiline RegExpObjectImp::Multiline None
+ $* RegExpObjectImp::Multiline DontEnum
+ lastMatch RegExpObjectImp::LastMatch DontDelete|ReadOnly
+ $& RegExpObjectImp::LastMatch DontDelete|ReadOnly|DontEnum
+ lastParen RegExpObjectImp::LastParen DontDelete|ReadOnly
+ $+ RegExpObjectImp::LastParen DontDelete|ReadOnly|DontEnum
+ leftContext RegExpObjectImp::LeftContext DontDelete|ReadOnly
+ $` RegExpObjectImp::LeftContext DontDelete|ReadOnly|DontEnum
+ rightContext RegExpObjectImp::RightContext DontDelete|ReadOnly
+ $' RegExpObjectImp::RightContext DontDelete|ReadOnly|DontEnum
+ $1 RegExpObjectImp::Dollar1 DontDelete|ReadOnly
+ $2 RegExpObjectImp::Dollar2 DontDelete|ReadOnly
+ $3 RegExpObjectImp::Dollar3 DontDelete|ReadOnly
+ $4 RegExpObjectImp::Dollar4 DontDelete|ReadOnly
+ $5 RegExpObjectImp::Dollar5 DontDelete|ReadOnly
+ $6 RegExpObjectImp::Dollar6 DontDelete|ReadOnly
+ $7 RegExpObjectImp::Dollar7 DontDelete|ReadOnly
+ $8 RegExpObjectImp::Dollar8 DontDelete|ReadOnly
+ $9 RegExpObjectImp::Dollar9 DontDelete|ReadOnly
+@end
+*/
+
+struct RegExpObjectImpPrivate {
+ // Global search cache / settings
+ RegExpObjectImpPrivate() : lastNumSubPatterns(0), multiline(false) { }
+ UString lastInput;
+ OwnArrayPtr<int> lastOvector;
+ unsigned lastNumSubPatterns : 31;
+ bool multiline : 1;
+};
+
+RegExpObjectImp::RegExpObjectImp(ExecState* exec, FunctionPrototype* funcProto, RegExpPrototype* regProto)
+ : InternalFunctionImp(funcProto, "RegExp")
+ , d(new RegExpObjectImpPrivate)
+{
+ // ECMA 15.10.5.1 RegExp.prototype
+ putDirect(exec->propertyNames().prototype, regProto, DontEnum | DontDelete | ReadOnly);
+
+ // no. of arguments for constructor
+ putDirect(exec->propertyNames().length, jsNumber(2), ReadOnly | DontDelete | DontEnum);
+}
+
+/*
+ To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular
+ expression matching through the performMatch function. We use cached results to calculate,
+ e.g., RegExp.lastMatch and RegExp.leftParen.
+*/
+void RegExpObjectImp::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector)
+{
+ OwnArrayPtr<int> tmpOvector;
+ position = r->match(s, startOffset, &tmpOvector);
+
+ if (ovector)
+ *ovector = tmpOvector.get();
+
+ if (position != -1) {
+ ASSERT(tmpOvector);
+
+ length = tmpOvector[1] - tmpOvector[0];
+
+ d->lastInput = s;
+ d->lastOvector.set(tmpOvector.release());
+ d->lastNumSubPatterns = r->numSubpatterns();
+ }
+}
+
+JSObject* RegExpObjectImp::arrayOfMatches(ExecState* exec) const
+{
+ unsigned lastNumSubpatterns = d->lastNumSubPatterns;
+ ArrayInstance* arr = new ArrayInstance(exec->lexicalGlobalObject()->arrayPrototype(), lastNumSubpatterns + 1);
+ for (unsigned i = 0; i <= lastNumSubpatterns; ++i) {
+ int start = d->lastOvector[2 * i];
+ if (start >= 0)
+ arr->put(exec, i, jsString(d->lastInput.substr(start, d->lastOvector[2 * i + 1] - start)));
+ }
+ arr->put(exec, exec->propertyNames().index, jsNumber(d->lastOvector[0]));
+ arr->put(exec, exec->propertyNames().input, jsString(d->lastInput));
+ return arr;
+}
+
+JSValue* RegExpObjectImp::getBackref(unsigned i) const
+{
+ if (d->lastOvector && i <= d->lastNumSubPatterns)
+ return jsString(d->lastInput.substr(d->lastOvector[2 * i], d->lastOvector[2 * i + 1] - d->lastOvector[2 * i]));
+ return jsString("");
+}
+
+JSValue* RegExpObjectImp::getLastParen() const
+{
+ unsigned i = d->lastNumSubPatterns;
+ if (i > 0) {
+ ASSERT(d->lastOvector);
+ return jsString(d->lastInput.substr(d->lastOvector[2 * i], d->lastOvector[2 * i + 1] - d->lastOvector[2 * i]));
+ }
+ return jsString("");
+}
+
+JSValue *RegExpObjectImp::getLeftContext() const
+{
+ if (d->lastOvector)
+ return jsString(d->lastInput.substr(0, d->lastOvector[0]));
+ return jsString("");
+}
+
+JSValue *RegExpObjectImp::getRightContext() const
+{
+ if (d->lastOvector) {
+ UString s = d->lastInput;
+ return jsString(s.substr(d->lastOvector[1], s.size() - d->lastOvector[1]));
+ }
+ return jsString("");
+}
+
+bool RegExpObjectImp::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ return getStaticValueSlot<RegExpObjectImp, InternalFunctionImp>(exec, &RegExpObjectImpTable, this, propertyName, slot);
+}
+
+JSValue *RegExpObjectImp::getValueProperty(ExecState*, int token) const
+{
+ switch (token) {
+ case Dollar1:
+ return getBackref(1);
+ case Dollar2:
+ return getBackref(2);
+ case Dollar3:
+ return getBackref(3);
+ case Dollar4:
+ return getBackref(4);
+ case Dollar5:
+ return getBackref(5);
+ case Dollar6:
+ return getBackref(6);
+ case Dollar7:
+ return getBackref(7);
+ case Dollar8:
+ return getBackref(8);
+ case Dollar9:
+ return getBackref(9);
+ case Input:
+ return jsString(d->lastInput);
+ case Multiline:
+ return jsBoolean(d->multiline);
+ case LastMatch:
+ return getBackref(0);
+ case LastParen:
+ return getLastParen();
+ case LeftContext:
+ return getLeftContext();
+ case RightContext:
+ return getRightContext();
+ default:
+ ASSERT(0);
+ }
+
+ return jsString("");
+}
+
+void RegExpObjectImp::put(ExecState *exec, const Identifier &propertyName, JSValue *value)
+{
+ lookupPut<RegExpObjectImp, InternalFunctionImp>(exec, propertyName, value, &RegExpObjectImpTable, this);
+}
+
+void RegExpObjectImp::putValueProperty(ExecState *exec, int token, JSValue *value)
+{
+ switch (token) {
+ case Input:
+ d->lastInput = value->toString(exec);
+ break;
+ case Multiline:
+ d->multiline = value->toBoolean(exec);
+ break;
+ default:
+ ASSERT(0);
+ }
+}
+
+bool RegExpObjectImp::implementsConstruct() const
+{
+ return true;
+}
+
+// ECMA 15.10.4
+JSObject *RegExpObjectImp::construct(ExecState *exec, const List &args)
+{
+ JSValue* arg0 = args[0];
+ JSValue* arg1 = args[1];
+
+ if (arg0->isObject(&RegExpImp::info)) {
+ if (!arg1->isUndefined())
+ return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another.");
+ return static_cast<JSObject*>(arg0);
+ }
+
+ UString pattern = arg0->isUndefined() ? UString("") : arg0->toString(exec);
+ UString flags = arg1->isUndefined() ? UString("") : arg1->toString(exec);
+
+ return createRegExpImp(exec, RegExp::create(pattern, flags));
+}
+
+JSObject* RegExpObjectImp::createRegExpImp(ExecState* exec, PassRefPtr<RegExp> regExp)
+{
+ return regExp->isValid()
+ ? new RegExpImp(static_cast<RegExpPrototype*>(exec->lexicalGlobalObject()->regExpPrototype()), regExp)
+ : throwError(exec, SyntaxError, UString("Invalid regular expression: ").append(regExp->errorMessage()));
+}
+
+// ECMA 15.10.3
+JSValue *RegExpObjectImp::callAsFunction(ExecState *exec, JSObject * /*thisObj*/, const List &args)
+{
+ return construct(exec, args);
+}
+
+const UString& RegExpObjectImp::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->lastInput;
+}
+
+}
diff --git a/JavaScriptCore/kjs/regexp_object.h b/JavaScriptCore/kjs/regexp_object.h
new file mode 100644
index 0000000..c69e8f7
--- /dev/null
+++ b/JavaScriptCore/kjs/regexp_object.h
@@ -0,0 +1,105 @@
+/*
+ * 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 REGEXP_OBJECT_H_
+#define REGEXP_OBJECT_H_
+
+#include "function_object.h"
+#include "regexp.h"
+
+namespace KJS {
+
+ struct RegExpObjectImpPrivate;
+
+ class RegExpPrototype : public JSObject {
+ public:
+ RegExpPrototype(ExecState*, ObjectPrototype*, FunctionPrototype*);
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+ };
+
+ class RegExpImp : public JSObject {
+ public:
+ enum { Global, IgnoreCase, Multiline, Source, LastIndex };
+
+ RegExpImp(RegExpPrototype*, PassRefPtr<RegExp>);
+ virtual ~RegExpImp();
+
+ void setRegExp(PassRefPtr<RegExp> r) { m_regExp = r; }
+ RegExp* regExp() const { return m_regExp.get(); }
+
+ JSValue* test(ExecState*, const List& args);
+ JSValue* exec(ExecState*, const List& args);
+
+ virtual bool implementsCall() const;
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+ bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ JSValue* getValueProperty(ExecState*, int token) const;
+ void put(ExecState*, const Identifier&, JSValue*);
+ void putValueProperty(ExecState*, int token, JSValue*);
+
+ virtual const ClassInfo* classInfo() const { return &info; }
+ static const ClassInfo info;
+
+ void setLastIndex(double lastIndex) { m_lastIndex = lastIndex; }
+
+ private:
+ bool match(ExecState*, const List& args);
+
+ RefPtr<RegExp> m_regExp;
+ double m_lastIndex;
+ };
+
+ class RegExpObjectImp : public InternalFunctionImp {
+ public:
+ enum { Dollar1, Dollar2, Dollar3, Dollar4, Dollar5, Dollar6, Dollar7, Dollar8, Dollar9,
+ Input, Multiline, LastMatch, LastParen, LeftContext, RightContext };
+
+ RegExpObjectImp(ExecState*, FunctionPrototype*, RegExpPrototype*);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject* construct(ExecState*, const List&);
+ JSObject* createRegExpImp(ExecState*, PassRefPtr<RegExp>);
+ virtual JSValue* callAsFunction(ExecState*, JSObject*, const List&);
+ virtual void put(ExecState*, const Identifier&, JSValue*);
+ void putValueProperty(ExecState*, int token, JSValue*);
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ JSValue* getValueProperty(ExecState*, int token) const;
+ virtual const ClassInfo* classInfo() const { return &info; }
+
+ void performMatch(RegExp*, const UString&, int startOffset, int& position, int& length, int** ovector = 0);
+ JSObject* arrayOfMatches(ExecState*) const;
+ const UString& input() const;
+
+ private:
+ JSValue* getBackref(unsigned) const;
+ JSValue* getLastParen() const;
+ JSValue* getLeftContext() const;
+ JSValue* getRightContext() const;
+
+ OwnPtr<RegExpObjectImpPrivate> d;
+
+ static const ClassInfo info;
+ };
+
+} // namespace
+
+#endif
diff --git a/JavaScriptCore/kjs/scope_chain.cpp b/JavaScriptCore/kjs/scope_chain.cpp
new file mode 100644
index 0000000..aba066a
--- /dev/null
+++ b/JavaScriptCore/kjs/scope_chain.cpp
@@ -0,0 +1,63 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2003, 2006 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 "scope_chain.h"
+#include "PropertyNameArray.h"
+#include <stdio.h>
+#include "object.h"
+
+namespace KJS {
+
+void ScopeChain::push(const ScopeChain &c)
+{
+ ScopeChainNode **tail = &_node;
+ for (ScopeChainNode *n = c._node; n; n = n->next) {
+ ScopeChainNode *newNode = new ScopeChainNode(*tail, n->object);
+ *tail = newNode;
+ tail = &newNode->next;
+ }
+}
+
+#ifndef NDEBUG
+
+void ScopeChain::print()
+{
+ ScopeChainIterator scopeEnd = end();
+ for (ScopeChainIterator scopeIter = begin(); scopeIter != scopeEnd; ++scopeIter) {
+ JSObject* o = *scopeIter;
+ PropertyNameArray propertyNames;
+ // FIXME: should pass ExecState here!
+ o->getPropertyNames(0, propertyNames);
+ PropertyNameArray::const_iterator propEnd = propertyNames.end();
+
+ fprintf(stderr, "----- [scope %p] -----\n", o);
+ for (PropertyNameArray::const_iterator propIter = propertyNames.begin(); propIter != propEnd; propIter++) {
+ Identifier name = *propIter;
+ fprintf(stderr, "%s, ", name.ascii());
+ }
+ fprintf(stderr, "\n");
+ }
+}
+
+#endif
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/scope_chain.h b/JavaScriptCore/kjs/scope_chain.h
new file mode 100644
index 0000000..7441cb8
--- /dev/null
+++ b/JavaScriptCore/kjs/scope_chain.h
@@ -0,0 +1,156 @@
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 2003 Apple Computer, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef KJS_SCOPE_CHAIN_H
+#define KJS_SCOPE_CHAIN_H
+
+#include <wtf/Assertions.h>
+
+namespace KJS {
+
+ class JSObject;
+ class ExecState;
+
+ class ScopeChainNode {
+ public:
+ ScopeChainNode(ScopeChainNode *n, JSObject *o)
+ : next(n), object(o), refCount(1) { }
+
+ ScopeChainNode *next;
+ JSObject *object;
+ int refCount;
+ };
+
+ class ScopeChainIterator {
+ public:
+ ScopeChainIterator(ScopeChainNode *node) : m_node(node) {}
+
+ JSObject * const & operator*() const { return m_node->object; }
+ JSObject * const * operator->() const { return &(operator*()); }
+
+ ScopeChainIterator& operator++() { m_node = m_node->next; return *this; }
+
+ // postfix ++ intentionally omitted
+
+ bool operator==(const ScopeChainIterator& other) const { return m_node == other.m_node; }
+ bool operator!=(const ScopeChainIterator& other) const { return m_node != other.m_node; }
+
+ private:
+ ScopeChainNode *m_node;
+ };
+
+ class ScopeChain {
+ public:
+ typedef ScopeChainIterator const_iterator;
+ typedef JSObject* ValueType;
+
+ ScopeChain() : _node(0) { }
+ ~ScopeChain() { deref(); }
+
+ ScopeChain(const ScopeChain &c) : _node(c._node)
+ { if (_node) ++_node->refCount; }
+ ScopeChain &operator=(const ScopeChain &);
+
+ bool isEmpty() const { return !_node; }
+ JSObject *top() const { return _node->object; }
+
+ JSObject *bottom() const;
+
+ ScopeChainIterator begin() const { return ScopeChainIterator(_node); }
+ ScopeChainIterator end() const { return ScopeChainIterator(0); }
+
+ void clear() { deref(); _node = 0; }
+ void push(JSObject *);
+ void push(const ScopeChain &);
+ void replaceTop(JSObject*);
+ void pop();
+
+ void mark();
+
+#ifndef NDEBUG
+ void print();
+#endif
+
+ private:
+ ScopeChainNode *_node;
+
+ void deref() { if (_node && --_node->refCount == 0) release(); }
+ void ref() const;
+
+ void release();
+ };
+
+inline void ScopeChain::ref() const
+{
+ for (ScopeChainNode *n = _node; n; n = n->next) {
+ if (n->refCount++ != 0)
+ break;
+ }
+}
+
+inline ScopeChain &ScopeChain::operator=(const ScopeChain &c)
+{
+ c.ref();
+ deref();
+ _node = c._node;
+ return *this;
+}
+
+inline JSObject *ScopeChain::bottom() const
+{
+ ScopeChainNode *last = 0;
+ for (ScopeChainNode *n = _node; n; n = n->next)
+ last = n;
+ if (!last)
+ return 0;
+ return last->object;
+}
+
+inline void ScopeChain::push(JSObject *o)
+{
+ ASSERT(o);
+ _node = new ScopeChainNode(_node, o);
+}
+
+inline void ScopeChain::replaceTop(JSObject* o)
+{
+ ASSERT(o);
+ _node->object = o;
+}
+
+inline void ScopeChain::pop()
+{
+ ScopeChainNode *oldNode = _node;
+ ASSERT(oldNode);
+ ScopeChainNode *newNode = oldNode->next;
+ _node = newNode;
+
+ if (--oldNode->refCount != 0) {
+ if (newNode)
+ ++newNode->refCount;
+ } else {
+ delete oldNode;
+ }
+}
+
+} // namespace KJS
+
+#endif // KJS_SCOPE_CHAIN_H
diff --git a/JavaScriptCore/kjs/scope_chain_mark.h b/JavaScriptCore/kjs/scope_chain_mark.h
new file mode 100644
index 0000000..bc4d5f8
--- /dev/null
+++ b/JavaScriptCore/kjs/scope_chain_mark.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (C) 2003, 2006, 2008 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef scope_chain_mark_h
+#define scope_chain_mark_h
+
+#include "Activation.h"
+#include "scope_chain.h"
+
+namespace KJS {
+
+ inline void ScopeChain::mark()
+ {
+ for (ScopeChainNode* n = _node; n; n = n->next) {
+ JSObject* o = n->object;
+
+ // An ActivationImp that is on the activation stack can't have the
+ // JSObject::marked() method called on it, because it doesn't have an
+ // entry in a GC mark bitmap, so we check here whether it is on the
+ // stack and directly call the portion of the marking code that is
+ // still relevant.
+
+ if (o->isActivationObject() && static_cast<ActivationImp*>(o)->isOnStack())
+ static_cast<ActivationImp*>(o)->markChildren();
+ else if (!o->marked())
+ o->mark();
+ }
+ }
+
+} // namespace KJS
+
+#endif
diff --git a/JavaScriptCore/kjs/string_object.cpp b/JavaScriptCore/kjs/string_object.cpp
new file mode 100644
index 0000000..04d8ebb
--- /dev/null
+++ b/JavaScriptCore/kjs/string_object.cpp
@@ -0,0 +1,1051 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * 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 "string_object.h"
+#include "string_object.lut.h"
+
+#include "JSWrapperObject.h"
+#include "PropertyNameArray.h"
+#include "array_object.h"
+#include "error_object.h"
+#include "operations.h"
+#include "regexp_object.h"
+#include <wtf/MathExtras.h>
+#include <wtf/unicode/Unicode.h>
+
+#if PLATFORM(CF)
+#include <CoreFoundation/CoreFoundation.h>
+#elif PLATFORM(WIN_OS)
+#include <windows.h>
+#endif
+
+using namespace WTF;
+
+namespace KJS {
+
+// ------------------------------ StringInstance ----------------------------
+
+const ClassInfo StringInstance::info = { "String", 0, 0 };
+
+StringInstance::StringInstance(JSObject *proto)
+ : JSWrapperObject(proto)
+{
+ setInternalValue(jsString(""));
+}
+
+StringInstance::StringInstance(JSObject *proto, StringImp* string)
+ : JSWrapperObject(proto)
+{
+ setInternalValue(string);
+}
+
+StringInstance::StringInstance(JSObject *proto, const UString &string)
+ : JSWrapperObject(proto)
+{
+ setInternalValue(jsString(string));
+}
+
+JSValue *StringInstance::lengthGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot &slot)
+{
+ return jsNumber(static_cast<StringInstance*>(slot.slotBase())->internalValue()->value().size());
+}
+
+JSValue* StringInstance::indexGetter(ExecState*, JSObject*, const Identifier&, const PropertySlot& slot)
+{
+ return jsString(static_cast<StringInstance*>(slot.slotBase())->internalValue()->value().substr(slot.index(), 1));
+}
+
+static JSValue* stringInstanceNumericPropertyGetter(ExecState*, JSObject*, unsigned index, const PropertySlot& slot)
+{
+ return jsString(static_cast<StringInstance*>(slot.slotBase())->internalValue()->value().substr(index, 1));
+}
+
+bool StringInstance::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot)
+{
+ if (propertyName == exec->propertyNames().length) {
+ slot.setCustom(this, lengthGetter);
+ return true;
+ }
+
+ bool isStrictUInt32;
+ unsigned i = propertyName.toStrictUInt32(&isStrictUInt32);
+ unsigned length = internalValue()->value().size();
+ if (isStrictUInt32 && i < length) {
+ slot.setCustomIndex(this, i, indexGetter);
+ return true;
+ }
+
+ return JSObject::getOwnPropertySlot(exec, propertyName, slot);
+}
+
+bool StringInstance::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot)
+{
+ unsigned length = internalValue()->value().size();
+ if (propertyName < length) {
+ slot.setCustomNumeric(this, stringInstanceNumericPropertyGetter);
+ return true;
+ }
+
+ return JSObject::getOwnPropertySlot(exec, Identifier::from(propertyName), slot);
+}
+
+void StringInstance::put(ExecState* exec, const Identifier& propertyName, JSValue* value)
+{
+ if (propertyName == exec->propertyNames().length)
+ return;
+ JSObject::put(exec, propertyName, value);
+}
+
+bool StringInstance::deleteProperty(ExecState *exec, const Identifier &propertyName)
+{
+ if (propertyName == exec->propertyNames().length)
+ return false;
+ return JSObject::deleteProperty(exec, propertyName);
+}
+
+void StringInstance::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames)
+{
+ int size = internalValue()->getString().size();
+ for (int i = 0; i < size; i++)
+ propertyNames.add(Identifier(UString::from(i)));
+ return JSObject::getPropertyNames(exec, propertyNames);
+}
+
+// ------------------------------ StringPrototype ---------------------------
+const ClassInfo StringPrototype::info = { "String", &StringInstance::info, &stringTable };
+/* Source for string_object.lut.h
+@begin stringTable 26
+ toString &stringProtoFuncToString DontEnum|Function 0
+ valueOf &stringProtoFuncValueOf 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
+ toLocaleLowerCase &stringProtoFuncToLocaleLowerCase DontEnum|Function 0
+ toLocaleUpperCase &stringProtoFuncToLocaleUpperCase DontEnum|Function 0
+ localeCompare &stringProtoFuncLocaleCompare DontEnum|Function 1
+
+ big &stringProtoFuncBig DontEnum|Function 0
+ small &stringProtoFuncSmall DontEnum|Function 0
+ blink &stringProtoFuncBlink DontEnum|Function 0
+ bold &stringProtoFuncBold DontEnum|Function 0
+ fixed &stringProtoFuncFixed DontEnum|Function 0
+ italics &stringProtoFuncItalics DontEnum|Function 0
+ strike &stringProtoFuncStrike DontEnum|Function 0
+ sub &stringProtoFuncSub DontEnum|Function 0
+ sup &stringProtoFuncSup DontEnum|Function 0
+ fontcolor &stringProtoFuncFontcolor DontEnum|Function 1
+ fontsize &stringProtoFuncFontsize DontEnum|Function 1
+ anchor &stringProtoFuncAnchor DontEnum|Function 1
+ link &stringProtoFuncLink DontEnum|Function 1
+@end
+*/
+// ECMA 15.5.4
+StringPrototype::StringPrototype(ExecState* exec, ObjectPrototype* objProto)
+ : StringInstance(objProto)
+{
+ // The constructor will be added later, after StringObjectImp has been built
+ putDirect(exec->propertyNames().length, jsNumber(0), DontDelete | ReadOnly | DontEnum);
+}
+
+bool StringPrototype::getOwnPropertySlot(ExecState *exec, const Identifier& propertyName, PropertySlot &slot)
+{
+ return getStaticFunctionSlot<StringInstance>(exec, &stringTable, this, propertyName, slot);
+}
+
+// ------------------------------ Functions --------------------------
+
+static inline void expandSourceRanges(UString::Range * & array, int& count, int& capacity)
+{
+ int newCapacity;
+ if (capacity == 0) {
+ newCapacity = 16;
+ } else {
+ newCapacity = capacity * 2;
+ }
+
+ UString::Range *newArray = new UString::Range[newCapacity];
+ for (int i = 0; i < count; i++) {
+ newArray[i] = array[i];
+ }
+
+ delete [] array;
+
+ capacity = newCapacity;
+ array = newArray;
+}
+
+static void pushSourceRange(UString::Range * & array, int& count, int& capacity, UString::Range range)
+{
+ if (count + 1 > capacity)
+ expandSourceRanges(array, count, capacity);
+
+ array[count] = range;
+ count++;
+}
+
+static inline void expandReplacements(UString * & array, int& count, int& capacity)
+{
+ int newCapacity;
+ if (capacity == 0) {
+ newCapacity = 16;
+ } else {
+ newCapacity = capacity * 2;
+ }
+
+ UString *newArray = new UString[newCapacity];
+ for (int i = 0; i < count; i++) {
+ newArray[i] = array[i];
+ }
+
+ delete [] array;
+
+ capacity = newCapacity;
+ array = newArray;
+}
+
+static void pushReplacement(UString * & array, int& count, int& capacity, UString replacement)
+{
+ if (count + 1 > capacity)
+ expandReplacements(array, count, capacity);
+
+ array[count] = replacement;
+ count++;
+}
+
+static inline UString substituteBackreferences(const UString &replacement, const UString &source, int *ovector, RegExp *reg)
+{
+ UString substitutedReplacement = replacement;
+
+ int i = -1;
+ while ((i = substitutedReplacement.find(UString("$"), i + 1)) != -1) {
+ if (i+1 == substitutedReplacement.size())
+ break;
+
+ unsigned short ref = substitutedReplacement[i+1].unicode();
+ int backrefStart = 0;
+ int backrefLength = 0;
+ int advance = 0;
+
+ if (ref == '$') { // "$$" -> "$"
+ substitutedReplacement = substitutedReplacement.substr(0, i + 1) + substitutedReplacement.substr(i + 2);
+ continue;
+ } else if (ref == '&') {
+ backrefStart = ovector[0];
+ backrefLength = ovector[1] - backrefStart;
+ } else if (ref == '`') {
+ backrefStart = 0;
+ backrefLength = ovector[0];
+ } else if (ref == '\'') {
+ backrefStart = ovector[1];
+ backrefLength = source.size() - backrefStart;
+ } else if (ref >= '0' && ref <= '9') {
+ // 1- and 2-digit back references are allowed
+ unsigned backrefIndex = ref - '0';
+ if (backrefIndex > reg->numSubpatterns())
+ continue;
+ if (substitutedReplacement.size() > i + 2) {
+ ref = substitutedReplacement[i+2].unicode();
+ if (ref >= '0' && ref <= '9') {
+ backrefIndex = 10 * backrefIndex + ref - '0';
+ if (backrefIndex > reg->numSubpatterns())
+ backrefIndex = backrefIndex / 10; // Fall back to the 1-digit reference
+ else
+ advance = 1;
+ }
+ }
+ backrefStart = ovector[2 * backrefIndex];
+ backrefLength = ovector[2 * backrefIndex + 1] - backrefStart;
+ } else
+ continue;
+
+ substitutedReplacement = substitutedReplacement.substr(0, i) + source.substr(backrefStart, backrefLength) + substitutedReplacement.substr(i + 2 + advance);
+ i += backrefLength - 1; // - 1 offsets 'i + 1'
+ }
+
+ return substitutedReplacement;
+}
+static inline int localeCompare(const UString& a, const UString& b)
+{
+#if PLATFORM(WIN_OS)
+ int retval = CompareStringW(LOCALE_USER_DEFAULT, 0,
+ reinterpret_cast<LPCWSTR>(a.data()), a.size(),
+ reinterpret_cast<LPCWSTR>(b.data()), b.size());
+ return !retval ? retval : retval - 2;
+#elif PLATFORM(CF)
+ CFStringRef sa = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(a.data()), a.size(), kCFAllocatorNull);
+ CFStringRef sb = CFStringCreateWithCharactersNoCopy(kCFAllocatorDefault, reinterpret_cast<const UniChar*>(b.data()), b.size(), kCFAllocatorNull);
+
+ int retval = CFStringCompare(sa, sb, kCFCompareLocalized);
+
+ CFRelease(sa);
+ CFRelease(sb);
+
+ return retval;
+#else
+ return compare(a, b);
+#endif
+}
+
+static JSValue *replace(ExecState *exec, StringImp* sourceVal, JSValue *pattern, JSValue *replacement)
+{
+ UString source = sourceVal->value();
+ JSObject *replacementFunction = 0;
+ UString replacementString;
+
+ if (replacement->isObject() && replacement->toObject(exec)->implementsCall())
+ replacementFunction = replacement->toObject(exec);
+ else
+ replacementString = replacement->toString(exec);
+
+ if (pattern->isObject() && static_cast<JSObject *>(pattern)->inherits(&RegExpImp::info)) {
+ RegExp *reg = static_cast<RegExpImp *>(pattern)->regExp();
+ bool global = reg->global();
+
+ RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalGlobalObject()->regExpConstructor());
+
+ int lastIndex = 0;
+ int startPosition = 0;
+
+ UString::Range *sourceRanges = 0;
+ int sourceRangeCount = 0;
+ int sourceRangeCapacity = 0;
+ UString *replacements = 0;
+ int replacementCount = 0;
+ int replacementCapacity = 0;
+
+ // This is either a loop (if global is set) or a one-way (if not).
+ do {
+ int matchIndex;
+ int matchLen;
+ int* ovector;
+ regExpObj->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector);
+ if (matchIndex < 0)
+ break;
+
+ pushSourceRange(sourceRanges, sourceRangeCount, sourceRangeCapacity, UString::Range(lastIndex, matchIndex - lastIndex));
+
+ UString substitutedReplacement;
+ if (replacementFunction) {
+ int completeMatchStart = ovector[0];
+ List args;
+
+ for (unsigned i = 0; i < reg->numSubpatterns() + 1; i++) {
+ int matchStart = ovector[i * 2];
+ int matchLen = ovector[i * 2 + 1] - matchStart;
+
+ if (matchStart < 0)
+ args.append(jsUndefined());
+ else
+ args.append(jsString(source.substr(matchStart, matchLen)));
+ }
+
+ args.append(jsNumber(completeMatchStart));
+ args.append(sourceVal);
+
+ substitutedReplacement = replacementFunction->call(exec, exec->dynamicGlobalObject(),
+ args)->toString(exec);
+ } else
+ substitutedReplacement = substituteBackreferences(replacementString, source, ovector, reg);
+
+ pushReplacement(replacements, replacementCount, replacementCapacity, substitutedReplacement);
+
+ lastIndex = matchIndex + matchLen;
+ startPosition = lastIndex;
+
+ // special case of empty match
+ if (matchLen == 0) {
+ startPosition++;
+ if (startPosition > source.size())
+ break;
+ }
+ } while (global);
+
+ if (lastIndex < source.size())
+ pushSourceRange(sourceRanges, sourceRangeCount, sourceRangeCapacity, UString::Range(lastIndex, source.size() - lastIndex));
+
+ UString result;
+
+ if (sourceRanges)
+ result = source.spliceSubstringsWithSeparators(sourceRanges, sourceRangeCount, replacements, replacementCount);
+
+ delete [] sourceRanges;
+ delete [] replacements;
+
+ if (result == source)
+ return sourceVal;
+
+ return jsString(result);
+ }
+
+ // First arg is a string
+ UString patternString = pattern->toString(exec);
+ int matchPos = source.find(patternString);
+ int matchLen = patternString.size();
+ // Do the replacement
+ if (matchPos == -1)
+ return sourceVal;
+
+ if (replacementFunction) {
+ List args;
+
+ args.append(jsString(source.substr(matchPos, matchLen)));
+ args.append(jsNumber(matchPos));
+ args.append(sourceVal);
+
+ replacementString = replacementFunction->call(exec, exec->dynamicGlobalObject(),
+ args)->toString(exec);
+ }
+
+ return jsString(source.substr(0, matchPos) + replacementString + source.substr(matchPos + matchLen));
+}
+
+JSValue* stringProtoFuncToString(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&StringInstance::info))
+ return throwError(exec, TypeError);
+
+ return static_cast<StringInstance*>(thisObj)->internalValue();
+}
+
+JSValue* stringProtoFuncValueOf(ExecState* exec, JSObject* thisObj, const List&)
+{
+ if (!thisObj->inherits(&StringInstance::info))
+ return throwError(exec, TypeError);
+
+ return static_cast<StringInstance*>(thisObj)->internalValue();
+}
+
+JSValue* stringProtoFuncCharAt(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ UString u;
+ JSValue* a0 = args[0];
+ double dpos = a0->toInteger(exec);
+ if (dpos >= 0 && dpos < len)
+ u = s.substr(static_cast<int>(dpos), 1);
+ else
+ u = "";
+ return jsString(u);
+}
+
+JSValue* stringProtoFuncCharCodeAt(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* result = 0;
+
+ JSValue* a0 = args[0];
+ double dpos = a0->toInteger(exec);
+ if (dpos >= 0 && dpos < len)
+ result = jsNumber(s[static_cast<int>(dpos)].unicode());
+ else
+ result = jsNaN();
+ return result;
+}
+
+JSValue* stringProtoFuncConcat(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ List::const_iterator end = args.end();
+ for (List::const_iterator it = args.begin(); it != end; ++it) {
+ s += (*it)->toString(exec);
+ }
+ return jsString(s);
+}
+
+JSValue* stringProtoFuncIndexOf(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+ UString u2 = a0->toString(exec);
+ double dpos = a1->toInteger(exec);
+ if (dpos < 0)
+ dpos = 0;
+ else if (dpos > len)
+ dpos = len;
+ return jsNumber(s.find(u2, static_cast<int>(dpos)));
+}
+
+JSValue* stringProtoFuncLastIndexOf(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
+ UString u2 = a0->toString(exec);
+ double dpos = a1->toIntegerPreserveNaN(exec);
+ if (dpos < 0)
+ dpos = 0;
+ else if (!(dpos <= len)) // true for NaN
+ dpos = len;
+ return jsNumber(s.rfind(u2, static_cast<int>(dpos)));
+}
+
+JSValue* stringProtoFuncMatch(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ JSValue* a0 = args[0];
+
+ UString u = s;
+ RefPtr<RegExp> reg;
+ RegExpImp* imp = 0;
+ if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpImp::info)) {
+ reg = static_cast<RegExpImp *>(a0)->regExp();
+ } else {
+ /*
+ * ECMA 15.5.4.12 String.prototype.search (regexp)
+ * If regexp is not an object whose [[Class]] property is "RegExp", it is
+ * replaced with the result of the expression new RegExp(regexp).
+ */
+ reg = RegExp::create(a0->toString(exec));
+ }
+ RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalGlobalObject()->regExpConstructor());
+ int pos;
+ int matchLength;
+ regExpObj->performMatch(reg.get(), u, 0, pos, matchLength);
+ JSValue* result;
+ if (!(reg->global())) {
+ // case without 'g' flag is handled like RegExp.prototype.exec
+ if (pos < 0)
+ result = jsNull();
+ else
+ result = regExpObj->arrayOfMatches(exec);
+ } else {
+ // return array of matches
+ List list;
+ int lastIndex = 0;
+ while (pos >= 0) {
+ list.append(jsString(u.substr(pos, matchLength)));
+ lastIndex = pos;
+ pos += matchLength == 0 ? 1 : matchLength;
+ regExpObj->performMatch(reg.get(), u, pos, pos, matchLength);
+ }
+ if (imp)
+ imp->setLastIndex(lastIndex);
+ if (list.isEmpty()) {
+ // if there are no matches at all, it's important to return
+ // Null instead of an empty array, because this matches
+ // other browsers and because Null is a false value.
+ result = jsNull();
+ } else {
+ result = exec->lexicalGlobalObject()->arrayConstructor()->construct(exec, list);
+ }
+ }
+ return result;
+}
+
+JSValue* stringProtoFuncSearch(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ JSValue* a0 = args[0];
+
+ UString u = s;
+ RefPtr<RegExp> reg;
+ if (a0->isObject() && static_cast<JSObject*>(a0)->inherits(&RegExpImp::info)) {
+ reg = static_cast<RegExpImp*>(a0)->regExp();
+ } else {
+ /*
+ * ECMA 15.5.4.12 String.prototype.search (regexp)
+ * If regexp is not an object whose [[Class]] property is "RegExp", it is
+ * replaced with the result of the expression new RegExp(regexp).
+ */
+ reg = RegExp::create(a0->toString(exec));
+ }
+ RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalGlobalObject()->regExpConstructor());
+ int pos;
+ int matchLength;
+ regExpObj->performMatch(reg.get(), u, 0, pos, matchLength);
+ return jsNumber(pos);
+}
+
+JSValue* stringProtoFuncReplace(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ StringImp* sVal = thisObj->inherits(&StringInstance::info) ?
+ static_cast<StringInstance*>(thisObj)->internalValue() :
+ static_cast<StringImp*>(jsString(s));
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
+ return replace(exec, sVal, a0, a1);
+}
+
+JSValue* stringProtoFuncSlice(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[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 jsString(s.substr(static_cast<int>(from), static_cast<int>(to - from)));
+ }
+
+ return jsString("");
+}
+
+JSValue* stringProtoFuncSplit(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
+ JSObject *constructor = exec->lexicalGlobalObject()->arrayConstructor();
+ JSObject* res = static_cast<JSObject*>(constructor->construct(exec, exec->emptyList()));
+ JSValue* result = res;
+ UString u = s;
+ int pos;
+ int i = 0;
+ int p0 = 0;
+ uint32_t limit = a1->isUndefined() ? 0xFFFFFFFFU : a1->toUInt32(exec);
+ if (a0->isObject() && static_cast<JSObject *>(a0)->inherits(&RegExpImp::info)) {
+ RegExp *reg = static_cast<RegExpImp *>(a0)->regExp();
+ if (u.isEmpty() && reg->match(u, 0) >= 0) {
+ // empty string matched by regexp -> empty array
+ res->put(exec, exec->propertyNames().length, jsNumber(0));
+ return result;
+ }
+ pos = 0;
+ while (static_cast<uint32_t>(i) != limit && pos < u.size()) {
+ OwnArrayPtr<int> ovector;
+ int mpos = reg->match(u, pos, &ovector);
+ if (mpos < 0)
+ break;
+ int mlen = ovector[1] - ovector[0];
+ pos = mpos + (mlen == 0 ? 1 : mlen);
+ if (mpos != p0 || mlen) {
+ res->put(exec,i, jsString(u.substr(p0, mpos-p0)));
+ p0 = mpos + mlen;
+ i++;
+ }
+ for (unsigned si = 1; si <= reg->numSubpatterns(); ++si) {
+ int spos = ovector[si * 2];
+ if (spos < 0)
+ res->put(exec, i++, jsUndefined());
+ else
+ res->put(exec, i++, jsString(u.substr(spos, ovector[si * 2 + 1] - spos)));
+ }
+ }
+ } else {
+ UString u2 = a0->toString(exec);
+ if (u2.isEmpty()) {
+ if (u.isEmpty()) {
+ // empty separator matches empty string -> empty array
+ res->put(exec, exec->propertyNames().length, jsNumber(0));
+ return result;
+ } else {
+ while (static_cast<uint32_t>(i) != limit && i < u.size()-1)
+ res->put(exec, i++, jsString(u.substr(p0++, 1)));
+ }
+ } else {
+ while (static_cast<uint32_t>(i) != limit && (pos = u.find(u2, p0)) >= 0) {
+ res->put(exec, i, jsString(u.substr(p0, pos-p0)));
+ p0 = pos + u2.size();
+ i++;
+ }
+ }
+ }
+ // add remaining string, if any
+ if (static_cast<uint32_t>(i) != limit)
+ res->put(exec, i++, jsString(u.substr(p0)));
+ res->put(exec, exec->propertyNames().length, jsNumber(i));
+ return result;
+}
+
+JSValue* stringProtoFuncSubstr(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
+ double start = a0->toInteger(exec);
+ double length = a1->isUndefined() ? len : a1->toInteger(exec);
+ if (start >= len)
+ return jsString("");
+ if (length < 0)
+ return jsString("");
+ if (start < 0) {
+ start += len;
+ if (start < 0)
+ start = 0;
+ }
+ if (length > len)
+ length = len;
+ return jsString(s.substr(static_cast<int>(start), static_cast<int>(length)));
+}
+
+JSValue* stringProtoFuncSubstring(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ int len = s.size();
+
+ JSValue* a0 = args[0];
+ JSValue* a1 = args[1];
+
+ double start = a0->toNumber(exec);
+ double end = a1->toNumber(exec);
+ if (isnan(start))
+ start = 0;
+ if (isnan(end))
+ end = 0;
+ if (start < 0)
+ start = 0;
+ if (end < 0)
+ end = 0;
+ if (start > len)
+ start = len;
+ if (end > len)
+ end = len;
+ if (a1->isUndefined())
+ end = len;
+ if (start > end) {
+ double temp = end;
+ end = start;
+ start = temp;
+ }
+ return jsString(s.substr((int)start, (int)end-(int)start));
+}
+
+JSValue* stringProtoFuncToLowerCase(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ StringImp* sVal = thisObj->inherits(&StringInstance::info)
+ ? static_cast<StringInstance*>(thisObj)->internalValue()
+ : static_cast<StringImp*>(jsString(s));
+ int ssize = s.size();
+ if (!ssize)
+ return sVal;
+ Vector< ::UChar> buffer(ssize);
+ bool error;
+ int length = Unicode::toLower(buffer.data(), ssize, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error) {
+ buffer.resize(length);
+ length = Unicode::toLower(buffer.data(), length, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error)
+ return sVal;
+ }
+ if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
+ return sVal;
+ return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
+}
+
+JSValue* stringProtoFuncToUpperCase(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ StringImp* sVal = thisObj->inherits(&StringInstance::info)
+ ? static_cast<StringInstance*>(thisObj)->internalValue()
+ : static_cast<StringImp*>(jsString(s));
+ int ssize = s.size();
+ if (!ssize)
+ return sVal;
+ Vector< ::UChar> buffer(ssize);
+ bool error;
+ int length = Unicode::toUpper(buffer.data(), ssize, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error) {
+ buffer.resize(length);
+ length = Unicode::toUpper(buffer.data(), length, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error)
+ return sVal;
+ }
+ if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
+ return sVal;
+ return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
+}
+
+JSValue* stringProtoFuncToLocaleLowerCase(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ // FIXME: See http://www.unicode.org/Public/UNIDATA/SpecialCasing.txt for locale-sensitive mappings that aren't implemented.
+ StringImp* sVal = thisObj->inherits(&StringInstance::info)
+ ? static_cast<StringInstance*>(thisObj)->internalValue()
+ : static_cast<StringImp*>(jsString(s));
+ int ssize = s.size();
+ if (!ssize)
+ return sVal;
+ Vector< ::UChar> buffer(ssize);
+ bool error;
+ int length = Unicode::toLower(buffer.data(), ssize, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error) {
+ buffer.resize(length);
+ length = Unicode::toLower(buffer.data(), length, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error)
+ return sVal;
+ }
+ if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
+ return sVal;
+ return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
+}
+
+JSValue* stringProtoFuncToLocaleUpperCase(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+
+ StringImp* sVal = thisObj->inherits(&StringInstance::info)
+ ? static_cast<StringInstance*>(thisObj)->internalValue()
+ : static_cast<StringImp*>(jsString(s));
+ int ssize = s.size();
+ if (!ssize)
+ return sVal;
+ Vector< ::UChar> buffer(ssize);
+ bool error;
+ int length = Unicode::toUpper(buffer.data(), ssize, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error) {
+ buffer.resize(length);
+ length = Unicode::toUpper(buffer.data(), length, reinterpret_cast<const ::UChar*>(s.data()), ssize, &error);
+ if (error)
+ return sVal;
+ }
+ if (length == ssize && memcmp(buffer.data(), s.data(), length * sizeof(UChar)) == 0)
+ return sVal;
+ return jsString(UString(reinterpret_cast<UChar*>(buffer.releaseBuffer()), length, false));
+}
+
+JSValue* stringProtoFuncLocaleCompare(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ if (args.size() < 1)
+ return jsNumber(0);
+
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsNumber(localeCompare(s, a0->toString(exec)));
+}
+
+JSValue* stringProtoFuncBig(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<big>" + s + "</big>");
+}
+
+JSValue* stringProtoFuncSmall(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<small>" + s + "</small>");
+}
+
+JSValue* stringProtoFuncBlink(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<blink>" + s + "</blink>");
+}
+
+JSValue* stringProtoFuncBold(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<b>" + s + "</b>");
+}
+
+JSValue* stringProtoFuncFixed(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<tt>" + s + "</tt>");
+}
+
+JSValue* stringProtoFuncItalics(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<i>" + s + "</i>");
+}
+
+JSValue* stringProtoFuncStrike(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<strike>" + s + "</strike>");
+}
+
+JSValue* stringProtoFuncSub(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<sub>" + s + "</sub>");
+}
+
+JSValue* stringProtoFuncSup(ExecState* exec, JSObject* thisObj, const List&)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ return jsString("<sup>" + s + "</sup>");
+}
+
+JSValue* stringProtoFuncFontcolor(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsString("<font color=\"" + a0->toString(exec) + "\">" + s + "</font>");
+}
+
+JSValue* stringProtoFuncFontsize(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsString("<font size=\"" + a0->toString(exec) + "\">" + s + "</font>");
+}
+
+JSValue* stringProtoFuncAnchor(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsString("<a name=\"" + a0->toString(exec) + "\">" + s + "</a>");
+}
+
+JSValue* stringProtoFuncLink(ExecState* exec, JSObject* thisObj, const List& args)
+{
+ // This optimizes the common case that thisObj is a StringInstance
+ UString s = thisObj->inherits(&StringInstance::info) ? static_cast<StringInstance*>(thisObj)->internalValue()->value() : thisObj->toString(exec);
+ JSValue* a0 = args[0];
+ return jsString("<a href=\"" + a0->toString(exec) + "\">" + s + "</a>");
+}
+
+// ------------------------------ StringObjectImp ------------------------------
+
+StringObjectImp::StringObjectImp(ExecState* exec, FunctionPrototype* funcProto, StringPrototype* stringProto)
+ : InternalFunctionImp(funcProto, stringProto->classInfo()->className)
+{
+ // ECMA 15.5.3.1 String.prototype
+ putDirect(exec->propertyNames().prototype, stringProto, DontEnum|DontDelete|ReadOnly);
+
+ putDirectFunction(new StringObjectFuncImp(exec, funcProto, exec->propertyNames().fromCharCode), DontEnum);
+
+ // no. of arguments for constructor
+ putDirect(exec->propertyNames().length, jsNumber(1), ReadOnly|DontDelete|DontEnum);
+}
+
+
+bool StringObjectImp::implementsConstruct() const
+{
+ return true;
+}
+
+// ECMA 15.5.2
+JSObject *StringObjectImp::construct(ExecState *exec, const List &args)
+{
+ JSObject *proto = exec->lexicalGlobalObject()->stringPrototype();
+ if (args.size() == 0)
+ return new StringInstance(proto);
+ return new StringInstance(proto, args[0]->toString(exec));
+}
+
+// ECMA 15.5.1
+JSValue *StringObjectImp::callAsFunction(ExecState *exec, JSObject* /*thisObj*/, const List &args)
+{
+ if (args.isEmpty())
+ return jsString("");
+ else {
+ JSValue *v = args[0];
+ return jsString(v->toString(exec));
+ }
+}
+
+// ------------------------------ StringObjectFuncImp --------------------------
+
+// ECMA 15.5.3.2 fromCharCode()
+StringObjectFuncImp::StringObjectFuncImp(ExecState* exec, FunctionPrototype* funcProto, const Identifier& name)
+ : InternalFunctionImp(funcProto, name)
+{
+ putDirect(exec->propertyNames().length, jsNumber(1), DontDelete|ReadOnly|DontEnum);
+}
+
+JSValue *StringObjectFuncImp::callAsFunction(ExecState *exec, JSObject* /*thisObj*/, const List &args)
+{
+ UString s;
+ if (args.size()) {
+ UChar *buf = static_cast<UChar *>(fastMalloc(args.size() * sizeof(UChar)));
+ UChar *p = buf;
+ List::const_iterator end = args.end();
+ for (List::const_iterator it = args.begin(); it != end; ++it) {
+ unsigned short u = static_cast<unsigned short>((*it)->toUInt32(exec));
+ *p++ = UChar(u);
+ }
+ s = UString(buf, args.size(), false);
+ } else
+ s = "";
+
+ return jsString(s);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/string_object.h b/JavaScriptCore/kjs/string_object.h
new file mode 100644
index 0000000..8508788
--- /dev/null
+++ b/JavaScriptCore/kjs/string_object.h
@@ -0,0 +1,153 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ *
+ */
+
+#ifndef STRING_OBJECT_H_
+#define STRING_OBJECT_H_
+
+#include "function_object.h"
+#include "JSWrapperObject.h"
+#include "internal.h"
+#include "lookup.h"
+
+namespace KJS {
+
+ class StringInstance : public JSWrapperObject {
+ public:
+ StringInstance(JSObject *proto);
+ StringInstance(JSObject *proto, StringImp*);
+ StringInstance(JSObject *proto, const UString&);
+
+ virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&);
+ virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&);
+
+ virtual void put(ExecState* exec, const Identifier& propertyName, JSValue*);
+ virtual bool deleteProperty(ExecState* exec, const Identifier& propertyName);
+ virtual void getPropertyNames(ExecState*, PropertyNameArray&);
+
+ virtual const ClassInfo *classInfo() const { return &info; }
+ static const ClassInfo info;
+
+ StringImp* internalValue() const { return static_cast<StringImp*>(JSWrapperObject::internalValue());}
+
+ private:
+ bool inlineGetOwnPropertySlot(ExecState*, unsigned, PropertySlot&);
+
+ static JSValue* lengthGetter(ExecState*, JSObject *, const Identifier&, const PropertySlot&);
+ static JSValue* indexGetter(ExecState*, JSObject *, const Identifier&, const PropertySlot&);
+ };
+
+ // WebCore uses this to make style.filter undetectable
+ class StringInstanceThatMasqueradesAsUndefined : public StringInstance {
+ public:
+ StringInstanceThatMasqueradesAsUndefined(JSObject* proto, const UString& string)
+ : StringInstance(proto, string) { }
+ virtual bool masqueradeAsUndefined() const { return true; }
+ virtual bool toBoolean(ExecState*) const { return false; }
+ };
+
+ /**
+ * @internal
+ *
+ * The initial value of String.prototype (and thus all objects created
+ * with the String constructor
+ */
+ class StringPrototype : public StringInstance {
+ public:
+ StringPrototype(ExecState *exec,
+ ObjectPrototype *objProto);
+ virtual bool getOwnPropertySlot(ExecState *, const Identifier&, PropertySlot&);
+ virtual const ClassInfo *classInfo() const { return &info; }
+ static const ClassInfo info;
+ };
+
+ /**
+ * @internal
+ *
+ * Functions to implement all methods that are properties of the
+ * String.prototype object
+ */
+
+ JSValue* stringProtoFuncToString(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncValueOf(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncCharAt(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncCharCodeAt(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncConcat(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncIndexOf(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncLastIndexOf(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncMatch(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncReplace(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncSearch(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncSlice(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncSplit(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncSubstr(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncSubstring(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncToLowerCase(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncToUpperCase(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncToLocaleLowerCase(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncToLocaleUpperCase(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncLocaleCompare(ExecState*, JSObject*, const List&);
+
+ JSValue* stringProtoFuncBig(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncSmall(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncBlink(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncBold(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncFixed(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncItalics(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncStrike(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncSub(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncSup(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncFontcolor(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncFontsize(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncAnchor(ExecState*, JSObject*, const List&);
+ JSValue* stringProtoFuncLink(ExecState*, JSObject*, const List&);
+
+ /**
+ * @internal
+ *
+ * The initial value of the the global variable's "String" property
+ */
+ class StringObjectImp : public InternalFunctionImp {
+ public:
+ StringObjectImp(ExecState *exec,
+ FunctionPrototype *funcProto,
+ StringPrototype *stringProto);
+
+ virtual bool implementsConstruct() const;
+ virtual JSObject *construct(ExecState *exec, const List &args);
+ virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
+ };
+
+ /**
+ * @internal
+ *
+ * Class to implement all methods that are properties of the
+ * String object
+ */
+ class StringObjectFuncImp : public InternalFunctionImp {
+ public:
+ StringObjectFuncImp(ExecState*, FunctionPrototype*, const Identifier&);
+ virtual JSValue *callAsFunction(ExecState *exec, JSObject *thisObj, const List &args);
+ };
+
+} // namespace
+
+#endif
+
diff --git a/JavaScriptCore/kjs/testkjs.cpp b/JavaScriptCore/kjs/testkjs.cpp
new file mode 100644
index 0000000..c229336
--- /dev/null
+++ b/JavaScriptCore/kjs/testkjs.cpp
@@ -0,0 +1,374 @@
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
+ * Copyright (C) 2006 Bjoern Graf (bjoern.graf@gmail.com)
+ *
+ * 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 "JSGlobalObject.h"
+#include "JSLock.h"
+#include "Parser.h"
+#include "array_object.h"
+#include "collector.h"
+#include "function.h"
+#include "interpreter.h"
+#include "nodes.h"
+#include "object.h"
+#include "protect.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+#include <wtf/Assertions.h>
+#include <wtf/HashTraits.h>
+
+#if HAVE(SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+#if PLATFORM(WIN_OS)
+#include <crtdbg.h>
+#include <windows.h>
+#endif
+
+#if PLATFORM(QT)
+#include <QDateTime>
+#endif
+
+using namespace KJS;
+using namespace WTF;
+
+static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
+
+static JSValue* functionPrint(ExecState*, JSObject*, const List&);
+static JSValue* functionDebug(ExecState*, JSObject*, const List&);
+static JSValue* functionGC(ExecState*, JSObject*, const List&);
+static JSValue* functionVersion(ExecState*, JSObject*, const List&);
+static JSValue* functionRun(ExecState*, JSObject*, const List&);
+static JSValue* functionLoad(ExecState*, JSObject*, const List&);
+static JSValue* functionReadline(ExecState*, JSObject*, const List&);
+static JSValue* functionQuit(ExecState*, JSObject*, const List&);
+
+class StopWatch {
+public:
+ void start();
+ void stop();
+ long getElapsedMS(); // call stop() first
+
+private:
+#if PLATFORM(QT)
+ uint m_startTime;
+ uint m_stopTime;
+#elif PLATFORM(WIN_OS)
+ DWORD m_startTime;
+ DWORD m_stopTime;
+#else
+ // Windows does not have timeval, disabling this class for now (bug 7399)
+ timeval m_startTime;
+ timeval m_stopTime;
+#endif
+};
+
+void StopWatch::start()
+{
+#if PLATFORM(QT)
+ QDateTime t = QDateTime::currentDateTime();
+ m_startTime = t.toTime_t() * 1000 + t.time().msec();
+#elif PLATFORM(WIN_OS)
+ m_startTime = timeGetTime();
+#else
+ gettimeofday(&m_startTime, 0);
+#endif
+}
+
+void StopWatch::stop()
+{
+#if PLATFORM(QT)
+ QDateTime t = QDateTime::currentDateTime();
+ m_stopTime = t.toTime_t() * 1000 + t.time().msec();
+#elif PLATFORM(WIN_OS)
+ m_stopTime = timeGetTime();
+#else
+ gettimeofday(&m_stopTime, 0);
+#endif
+}
+
+long StopWatch::getElapsedMS()
+{
+#if PLATFORM(WIN_OS) || PLATFORM(QT)
+ return m_stopTime - m_startTime;
+#else
+ timeval elapsedTime;
+ timersub(&m_stopTime, &m_startTime, &elapsedTime);
+
+ return elapsedTime.tv_sec * 1000 + lroundf(elapsedTime.tv_usec / 1000.0f);
+#endif
+}
+
+class GlobalObject : public JSGlobalObject {
+public:
+ GlobalObject(Vector<UString>& arguments);
+ virtual UString className() const { return "global"; }
+};
+COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
+
+GlobalObject::GlobalObject(Vector<UString>& arguments)
+{
+ putDirectFunction(new PrototypeFunction(globalExec(), functionPrototype(), 1, "debug", functionDebug));
+ putDirectFunction(new PrototypeFunction(globalExec(), functionPrototype(), 1, "print", functionPrint));
+ putDirectFunction(new PrototypeFunction(globalExec(), functionPrototype(), 0, "quit", functionQuit));
+ putDirectFunction(new PrototypeFunction(globalExec(), functionPrototype(), 0, "gc", functionGC));
+ putDirectFunction(new PrototypeFunction(globalExec(), functionPrototype(), 1, "version", functionVersion));
+ putDirectFunction(new PrototypeFunction(globalExec(), functionPrototype(), 1, "run", functionRun));
+ putDirectFunction(new PrototypeFunction(globalExec(), functionPrototype(), 1, "load", functionLoad));
+ putDirectFunction(new PrototypeFunction(globalExec(), functionPrototype(), 0, "readline", functionReadline));
+
+ JSObject* array = arrayConstructor()->construct(globalExec(), globalExec()->emptyList());
+ for (size_t i = 0; i < arguments.size(); ++i)
+ array->put(globalExec(), i, jsString(arguments[i]));
+ putDirect("arguments", array);
+
+ Interpreter::setShouldPrintExceptions(true);
+}
+
+JSValue* functionPrint(ExecState* exec, JSObject*, const List& args)
+{
+ printf("%s\n", args[0]->toString(exec).UTF8String().c_str());
+ return jsUndefined();
+}
+
+JSValue* functionDebug(ExecState* exec, JSObject*, const List& args)
+{
+ fprintf(stderr, "--> %s\n", args[0]->toString(exec).UTF8String().c_str());
+ return jsUndefined();
+}
+
+JSValue* functionGC(ExecState*, JSObject*, const List&)
+{
+ JSLock lock;
+ Collector::collect();
+ return jsUndefined();
+}
+
+JSValue* functionVersion(ExecState*, JSObject*, const List&)
+{
+ // We need this function for compatibility with the Mozilla JS tests but for now
+ // we don't actually do any version-specific handling
+ return jsUndefined();
+}
+
+JSValue* functionRun(ExecState* exec, JSObject*, const List& args)
+{
+ StopWatch stopWatch;
+ UString fileName = args[0]->toString(exec);
+ Vector<char> script;
+ if (!fillBufferWithContentsOfFile(fileName, script))
+ return throwError(exec, GeneralError, "Could not open file.");
+
+ stopWatch.start();
+ Interpreter::evaluate(exec->dynamicGlobalObject()->globalExec(), fileName, 0, script.data());
+ stopWatch.stop();
+
+ return jsNumber(stopWatch.getElapsedMS());
+}
+
+JSValue* functionLoad(ExecState* exec, JSObject*, const List& args)
+{
+ UString fileName = args[0]->toString(exec);
+ Vector<char> script;
+ if (!fillBufferWithContentsOfFile(fileName, script))
+ return throwError(exec, GeneralError, "Could not open file.");
+
+ Interpreter::evaluate(exec->dynamicGlobalObject()->globalExec(), fileName, 0, script.data());
+
+ return jsUndefined();
+}
+
+JSValue* functionReadline(ExecState*, JSObject*, const List&)
+{
+ Vector<char, 256> line;
+ int c;
+ while ((c = getchar()) != EOF) {
+ // FIXME: Should we also break on \r?
+ if (c == '\n')
+ break;
+ line.append(c);
+ }
+ line.append('\0');
+ return jsString(line.data());
+}
+
+JSValue* functionQuit(ExecState*, JSObject*, const List&)
+{
+ exit(0);
+#if !COMPILER(MSVC)
+ // MSVC knows that exit(0) never returns, so it flags this return statement as unreachable.
+ return jsUndefined();
+#endif
+}
+
+// Use SEH for Release builds only to get rid of the crash report dialog
+// (luckily the same tests fail in Release and Debug builds so far). Need to
+// be in a separate main function because the kjsmain function requires object
+// unwinding.
+
+#if PLATFORM(WIN_OS) && !defined(_DEBUG)
+#define TRY __try {
+#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
+#else
+#define TRY
+#define EXCEPT(x)
+#endif
+
+int kjsmain(int argc, char** argv);
+
+int main(int argc, char** argv)
+{
+#if defined(_DEBUG) && PLATFORM(WIN_OS)
+ _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_FILE);
+ _CrtSetReportFile(_CRT_ASSERT, _CRTDBG_FILE_STDERR);
+ _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_FILE);
+#endif
+
+ int res = 0;
+ TRY
+ res = kjsmain(argc, argv);
+ EXCEPT(res = 3)
+ return res;
+}
+
+static bool prettyPrintScript(const UString& fileName, const Vector<char>& script)
+{
+ int errLine = 0;
+ UString errMsg;
+ UString scriptUString(script.data());
+ RefPtr<ProgramNode> programNode = parser().parse<ProgramNode>(fileName, 0, scriptUString.data(), scriptUString.size(), 0, &errLine, &errMsg);
+ if (!programNode) {
+ fprintf(stderr, "%s:%d: %s.\n", fileName.UTF8String().c_str(), errLine, errMsg.UTF8String().c_str());
+ return false;
+ }
+
+ printf("%s\n", programNode->toString().UTF8String().c_str());
+ return true;
+}
+
+static bool runWithScripts(const Vector<UString>& fileNames, Vector<UString>& arguments, bool prettyPrint)
+{
+ GlobalObject* globalObject = new GlobalObject(arguments);
+ Vector<char> script;
+
+ bool success = true;
+
+ for (size_t i = 0; i < fileNames.size(); i++) {
+ UString fileName = fileNames[i];
+
+ if (!fillBufferWithContentsOfFile(fileName, script))
+ return false; // fail early so we can catch missing files
+
+ if (prettyPrint)
+ prettyPrintScript(fileName, script);
+ else {
+ Completion completion = Interpreter::evaluate(globalObject->globalExec(), fileName, 0, script.data());
+ success = success && completion.complType() != Throw;
+ }
+ }
+ return success;
+}
+
+static void printUsageStatement()
+{
+ fprintf(stderr, "Usage: testkjs -f file1 [-f file2...][-p][-- arguments...]\n");
+ exit(-1);
+}
+
+static void parseArguments(int argc, char** argv, Vector<UString>& fileNames, Vector<UString>& arguments, bool& prettyPrint)
+{
+ if (argc < 3)
+ printUsageStatement();
+
+ int i = 1;
+ for (; i < argc; ++i) {
+ const char* arg = argv[i];
+ if (strcmp(arg, "-f") == 0) {
+ if (++i == argc)
+ printUsageStatement();
+ fileNames.append(argv[i]);
+ continue;
+ }
+ if (strcmp(arg, "-p") == 0) {
+ prettyPrint = true;
+ continue;
+ }
+ if (strcmp(arg, "--") == 0) {
+ ++i;
+ break;
+ }
+ break;
+ }
+
+ for (; i < argc; ++i)
+ arguments.append(argv[i]);
+}
+
+int kjsmain(int argc, char** argv)
+{
+ JSLock lock;
+
+ bool prettyPrint = false;
+ Vector<UString> fileNames;
+ Vector<UString> arguments;
+ parseArguments(argc, argv, fileNames, arguments, prettyPrint);
+
+ bool success = runWithScripts(fileNames, arguments, prettyPrint);
+
+#ifndef NDEBUG
+ Collector::collect();
+#endif
+
+ return success ? 0 : 3;
+}
+
+static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer)
+{
+ FILE* f = fopen(fileName.UTF8String().c_str(), "r");
+ if (!f) {
+ fprintf(stderr, "Could not open file: %s\n", fileName.UTF8String().c_str());
+ return false;
+ }
+
+ size_t buffer_size = 0;
+ size_t buffer_capacity = 1024;
+
+ buffer.resize(buffer_capacity);
+
+ while (!feof(f) && !ferror(f)) {
+ buffer_size += fread(buffer.data() + buffer_size, 1, buffer_capacity - buffer_size, f);
+ if (buffer_size == buffer_capacity) { // guarantees space for trailing '\0'
+ buffer_capacity *= 2;
+ buffer.resize(buffer_capacity);
+ }
+ }
+ fclose(f);
+ buffer[buffer_size] = '\0';
+
+ return true;
+}
diff --git a/JavaScriptCore/kjs/testkjs.pro b/JavaScriptCore/kjs/testkjs.pro
new file mode 100644
index 0000000..5a980eb
--- /dev/null
+++ b/JavaScriptCore/kjs/testkjs.pro
@@ -0,0 +1,38 @@
+TEMPLATE = app
+TARGET = testkjs
+DESTDIR = ..
+SOURCES = testkjs.cpp
+QT -= gui
+DEFINES -= KJS_IDENTIFIER_HIDE_GLOBALS
+INCLUDEPATH += $$PWD/.. $$PWD $$PWD/../bindings $$PWD/../bindings/c $$PWD/../wtf
+CONFIG -= app_bundle
+qt-port:DEFINES += BUILDING_QT__
+#qt-port:LIBS += -L$$OUTPUT_DIR/lib -lQtWebKit
+
+CONFIG += link_pkgconfig
+gtk-port:PKGCONFIG += glib-2.0 gobject-2.0 gthread-2.0
+
+gtk-port {
+ QMAKE_CXXFLAGS += $$system(icu-config --cppflags)
+ LIBS += $$system(icu-config --ldflags)
+}
+QMAKE_RPATHDIR += $$OUTPUT_DIR/lib
+
+isEmpty(OUTPUT_DIR):OUTPUT_DIR=$$PWD/../..
+include($$OUTPUT_DIR/config.pri)
+OBJECTS_DIR = tmp
+OBJECTS_DIR_WTR = $$OBJECTS_DIR/
+win32-*: OBJECTS_DIR_WTR ~= s|/|\|
+include($$PWD/../JavaScriptCore.pri)
+
+# Hack! Fix this.
+SOURCES -= API/JSBase.cpp \
+ API/JSCallbackConstructor.cpp \
+ API/JSCallbackFunction.cpp \
+ API/JSCallbackObject.cpp \
+ API/JSClassRef.cpp \
+ API/JSContextRef.cpp \
+ API/JSObjectRef.cpp \
+ API/JSStringRef.cpp \
+ API/JSValueRef.cpp
+
diff --git a/JavaScriptCore/kjs/types.h b/JavaScriptCore/kjs/types.h
new file mode 100644
index 0000000..603b2a2
--- /dev/null
+++ b/JavaScriptCore/kjs/types.h
@@ -0,0 +1,25 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * This file is part of the KDE libraries
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ *
+ * 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 "completion.h"
+#include "list.h"
diff --git a/JavaScriptCore/kjs/ustring.cpp b/JavaScriptCore/kjs/ustring.cpp
new file mode 100644
index 0000000..b658a8d
--- /dev/null
+++ b/JavaScriptCore/kjs/ustring.cpp
@@ -0,0 +1,1285 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
+ *
+ * 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 "JSLock.h"
+#include "collector.h"
+#include "dtoa.h"
+#include "function.h"
+#include "identifier.h"
+#include "operations.h"
+#include <ctype.h>
+#include <float.h>
+#include <limits.h>
+#include <math.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <wtf/Assertions.h>
+#include <wtf/ASCIICType.h>
+#include <wtf/MathExtras.h>
+#include <wtf/Vector.h>
+#include <wtf/unicode/UTF8.h>
+
+#if HAVE(STRING_H)
+#include <string.h>
+#endif
+#if HAVE(STRINGS_H)
+#include <strings.h>
+#endif
+
+using namespace WTF;
+using namespace WTF::Unicode;
+using namespace std;
+
+namespace KJS {
+
+extern const double NaN;
+extern const double Inf;
+
+static inline const size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); }
+static inline const size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); }
+
+static inline UChar* allocChars(size_t length)
+{
+ ASSERT(length);
+ if (length > maxUChars())
+ return 0;
+ return static_cast<UChar*>(fastMalloc(sizeof(UChar) * length));
+}
+
+static inline UChar* reallocChars(UChar* buffer, size_t length)
+{
+ ASSERT(length);
+ if (length > maxUChars())
+ return 0;
+ return static_cast<UChar*>(fastRealloc(buffer, sizeof(UChar) * length));
+}
+
+COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes)
+
+CString::CString(const char *c)
+{
+ length = strlen(c);
+ data = new char[length+1];
+ memcpy(data, c, length + 1);
+}
+
+CString::CString(const char *c, size_t len)
+{
+ length = len;
+ data = new char[len+1];
+ memcpy(data, c, len);
+ data[len] = 0;
+}
+
+CString::CString(const CString &b)
+{
+ length = b.length;
+ if (b.data) {
+ data = new char[length+1];
+ memcpy(data, b.data, length + 1);
+ }
+ else
+ data = 0;
+}
+
+CString::~CString()
+{
+ delete [] data;
+}
+
+CString &CString::append(const CString &t)
+{
+ char *n;
+ n = new char[length+t.length+1];
+ if (length)
+ memcpy(n, data, length);
+ if (t.length)
+ memcpy(n+length, t.data, t.length);
+ length += t.length;
+ n[length] = 0;
+
+ delete [] data;
+ data = n;
+
+ return *this;
+}
+
+CString &CString::operator=(const char *c)
+{
+ if (data)
+ delete [] data;
+ length = strlen(c);
+ data = new char[length+1];
+ memcpy(data, c, length + 1);
+
+ return *this;
+}
+
+CString &CString::operator=(const CString &str)
+{
+ if (this == &str)
+ return *this;
+
+ if (data)
+ delete [] data;
+ length = str.length;
+ if (str.data) {
+ data = new char[length + 1];
+ memcpy(data, str.data, length + 1);
+ }
+ else
+ data = 0;
+
+ return *this;
+}
+
+bool operator==(const CString& c1, const CString& c2)
+{
+ size_t len = c1.size();
+ return len == c2.size() && (len == 0 || memcmp(c1.c_str(), c2.c_str(), len) == 0);
+}
+
+// Hack here to avoid a global with a constructor; point to an unsigned short instead of a UChar.
+static unsigned short almostUChar;
+UString::Rep UString::Rep::null = { 0, 0, 1, 0, 0, &UString::Rep::null, 0, 0, 0, 0, 0, 0 };
+UString::Rep UString::Rep::empty = { 0, 0, 1, 0, 0, &UString::Rep::empty, 0, reinterpret_cast<UChar*>(&almostUChar), 0, 0, 0, 0 };
+const int normalStatBufferSize = 4096;
+static char *statBuffer = 0; // FIXME: This buffer is never deallocated.
+static int statBufferSize = 0;
+
+PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar *d, int l)
+{
+ ASSERT(JSLock::lockCount() > 0);
+
+ int sizeInBytes = l * sizeof(UChar);
+ UChar *copyD = static_cast<UChar *>(fastMalloc(sizeInBytes));
+ memcpy(copyD, d, sizeInBytes);
+
+ return create(copyD, l);
+}
+
+PassRefPtr<UString::Rep> UString::Rep::create(UChar *d, int l)
+{
+ ASSERT(JSLock::lockCount() > 0);
+
+ Rep* r = new Rep;
+ r->offset = 0;
+ r->len = l;
+ r->rc = 1;
+ r->_hash = 0;
+ r->isIdentifier = 0;
+ r->baseString = r;
+ r->reportedCost = 0;
+ r->buf = d;
+ r->usedCapacity = l;
+ r->capacity = l;
+ r->usedPreCapacity = 0;
+ r->preCapacity = 0;
+
+ // steal the single reference this Rep was created with
+ return adoptRef(r);
+}
+
+PassRefPtr<UString::Rep> UString::Rep::create(PassRefPtr<Rep> base, int offset, int length)
+{
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(base);
+
+ int baseOffset = base->offset;
+
+ base = base->baseString;
+
+ ASSERT(-(offset + baseOffset) <= base->usedPreCapacity);
+ ASSERT(offset + baseOffset + length <= base->usedCapacity);
+
+ Rep *r = new Rep;
+ r->offset = baseOffset + offset;
+ r->len = length;
+ r->rc = 1;
+ r->_hash = 0;
+ r->isIdentifier = 0;
+ r->baseString = base.releaseRef();
+ r->reportedCost = 0;
+ r->buf = 0;
+ r->usedCapacity = 0;
+ r->capacity = 0;
+ r->usedPreCapacity = 0;
+ r->preCapacity = 0;
+
+ // steal the single reference this Rep was created with
+ return adoptRef(r);
+}
+
+void UString::Rep::destroy()
+{
+ ASSERT(JSLock::lockCount() > 0);
+
+ if (isIdentifier)
+ Identifier::remove(this);
+ if (baseString != this) {
+ baseString->deref();
+ } else {
+ fastFree(buf);
+ }
+ delete this;
+}
+
+// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
+// or anything like that.
+const unsigned PHI = 0x9e3779b9U;
+
+// Paul Hsieh's SuperFastHash
+// http://www.azillionmonkeys.com/qed/hash.html
+unsigned UString::Rep::computeHash(const UChar *s, int len)
+{
+ unsigned l = len;
+ uint32_t hash = PHI;
+ uint32_t tmp;
+
+ int rem = l & 1;
+ l >>= 1;
+
+ // Main loop
+ for (; l > 0; l--) {
+ hash += s[0].uc;
+ tmp = (s[1].uc << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ s += 2;
+ hash += hash >> 11;
+ }
+
+ // Handle end case
+ if (rem) {
+ hash += s[0].uc;
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ }
+
+ // Force "avalanching" of final 127 bits
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 2;
+ hash += hash >> 15;
+ hash ^= hash << 10;
+
+ // this avoids ever returning a hash code of 0, since that is used to
+ // signal "hash not computed yet", using a value that is likely to be
+ // effectively the same as 0 when the low bits are masked
+ if (hash == 0)
+ hash = 0x80000000;
+
+ return hash;
+}
+
+// Paul Hsieh's SuperFastHash
+// http://www.azillionmonkeys.com/qed/hash.html
+unsigned UString::Rep::computeHash(const char *s)
+{
+ // This hash is designed to work on 16-bit chunks at a time. But since the normal case
+ // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
+ // were 16-bit chunks, which should give matching results
+
+ uint32_t hash = PHI;
+ uint32_t tmp;
+ size_t l = strlen(s);
+
+ size_t rem = l & 1;
+ l >>= 1;
+
+ // Main loop
+ for (; l > 0; l--) {
+ hash += (unsigned char)s[0];
+ tmp = ((unsigned char)s[1] << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ s += 2;
+ hash += hash >> 11;
+ }
+
+ // Handle end case
+ if (rem) {
+ hash += (unsigned char)s[0];
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ }
+
+ // Force "avalanching" of final 127 bits
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 2;
+ hash += hash >> 15;
+ hash ^= hash << 10;
+
+ // this avoids ever returning a hash code of 0, since that is used to
+ // signal "hash not computed yet", using a value that is likely to be
+ // effectively the same as 0 when the low bits are masked
+ if (hash == 0)
+ hash = 0x80000000;
+
+ return hash;
+}
+
+// put these early so they can be inlined
+inline size_t UString::expandedSize(size_t size, size_t otherSize) const
+{
+ // Do the size calculation in two parts, returning overflowIndicator if
+ // we overflow the maximum value that we can handle.
+
+ if (size > maxUChars())
+ return overflowIndicator();
+
+ size_t expandedSize = ((size + 10) / 10 * 11) + 1;
+ if (maxUChars() - expandedSize < otherSize)
+ return overflowIndicator();
+
+ return expandedSize + otherSize;
+}
+
+inline int UString::usedCapacity() const
+{
+ return m_rep->baseString->usedCapacity;
+}
+
+inline int UString::usedPreCapacity() const
+{
+ return m_rep->baseString->usedPreCapacity;
+}
+
+void UString::expandCapacity(int requiredLength)
+{
+ Rep* r = m_rep->baseString;
+
+ if (requiredLength > r->capacity) {
+ size_t newCapacity = expandedSize(requiredLength, r->preCapacity);
+ UChar* oldBuf = r->buf;
+ r->buf = reallocChars(r->buf, newCapacity);
+ if (!r->buf) {
+ r->buf = oldBuf;
+ m_rep = &Rep::null;
+ return;
+ }
+ r->capacity = newCapacity - r->preCapacity;
+ }
+ if (requiredLength > r->usedCapacity) {
+ r->usedCapacity = requiredLength;
+ }
+}
+
+void UString::expandPreCapacity(int requiredPreCap)
+{
+ Rep* r = m_rep->baseString;
+
+ if (requiredPreCap > r->preCapacity) {
+ size_t newCapacity = expandedSize(requiredPreCap, r->capacity);
+ int delta = newCapacity - r->capacity - r->preCapacity;
+
+ UChar* newBuf = allocChars(newCapacity);
+ if (!newBuf) {
+ m_rep = &Rep::null;
+ return;
+ }
+ memcpy(newBuf + delta, r->buf, (r->capacity + r->preCapacity) * sizeof(UChar));
+ fastFree(r->buf);
+ r->buf = newBuf;
+
+ r->preCapacity = newCapacity - r->capacity;
+ }
+ if (requiredPreCap > r->usedPreCapacity) {
+ r->usedPreCapacity = requiredPreCap;
+ }
+}
+
+UString::UString(const char *c)
+{
+ if (!c) {
+ m_rep = &Rep::null;
+ return;
+ }
+
+ if (!c[0]) {
+ m_rep = &Rep::empty;
+ return;
+ }
+
+ size_t length = strlen(c);
+ UChar *d = allocChars(length);
+ if (!d)
+ m_rep = &Rep::null;
+ else {
+ for (size_t i = 0; i < length; i++)
+ d[i].uc = c[i];
+ m_rep = Rep::create(d, static_cast<int>(length));
+ }
+}
+
+UString::UString(const UChar *c, int length)
+{
+ if (length == 0)
+ m_rep = &Rep::empty;
+ else
+ m_rep = Rep::createCopying(c, length);
+}
+
+UString::UString(UChar *c, int length, bool copy)
+{
+ if (length == 0)
+ m_rep = &Rep::empty;
+ else if (copy)
+ m_rep = Rep::createCopying(c, length);
+ else
+ m_rep = Rep::create(c, length);
+}
+
+UString::UString(const Vector<UChar>& buffer)
+{
+ if (!buffer.size())
+ m_rep = &Rep::empty;
+ else
+ m_rep = Rep::createCopying(buffer.data(), buffer.size());
+}
+
+
+UString::UString(const UString &a, const UString &b)
+{
+ int aSize = a.size();
+ int aOffset = a.m_rep->offset;
+ int bSize = b.size();
+ int bOffset = b.m_rep->offset;
+ int length = aSize + bSize;
+
+ // possible cases:
+
+ if (aSize == 0) {
+ // a is empty
+ m_rep = b.m_rep;
+ } else if (bSize == 0) {
+ // b is empty
+ m_rep = a.m_rep;
+ } else if (aOffset + aSize == a.usedCapacity() && aSize >= minShareSize && 4 * aSize >= bSize &&
+ (-bOffset != b.usedPreCapacity() || aSize >= bSize)) {
+ // - a reaches the end of its buffer so it qualifies for shared append
+ // - also, it's at least a quarter the length of b - appending to a much shorter
+ // string does more harm than good
+ // - however, if b qualifies for prepend and is longer than a, we'd rather prepend
+ UString x(a);
+ x.expandCapacity(aOffset + length);
+ if (a.data() && x.data()) {
+ memcpy(const_cast<UChar *>(a.data() + aSize), b.data(), bSize * sizeof(UChar));
+ m_rep = Rep::create(a.m_rep, 0, length);
+ } else
+ m_rep = &Rep::null;
+ } else if (-bOffset == b.usedPreCapacity() && bSize >= minShareSize && 4 * bSize >= aSize) {
+ // - b reaches the beginning of its buffer so it qualifies for shared prepend
+ // - also, it's at least a quarter the length of a - prepending to a much shorter
+ // string does more harm than good
+ UString y(b);
+ y.expandPreCapacity(-bOffset + aSize);
+ if (b.data() && y.data()) {
+ memcpy(const_cast<UChar *>(b.data() - aSize), a.data(), aSize * sizeof(UChar));
+ m_rep = Rep::create(b.m_rep, -aSize, length);
+ } else
+ m_rep = &Rep::null;
+ } else {
+ // a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string
+ size_t newCapacity = expandedSize(length, 0);
+ UChar* d = allocChars(newCapacity);
+ if (!d)
+ m_rep = &Rep::null;
+ else {
+ memcpy(d, a.data(), aSize * sizeof(UChar));
+ memcpy(d + aSize, b.data(), bSize * sizeof(UChar));
+ m_rep = Rep::create(d, length);
+ m_rep->capacity = newCapacity;
+ }
+ }
+}
+
+const UString& UString::null()
+{
+ static UString* n = new UString;
+ return *n;
+}
+
+UString UString::from(int i)
+{
+ UChar buf[1 + sizeof(i) * 3];
+ UChar *end = buf + sizeof(buf) / sizeof(UChar);
+ UChar *p = end;
+
+ if (i == 0) {
+ *--p = '0';
+ } else if (i == INT_MIN) {
+ char minBuf[1 + sizeof(i) * 3];
+ sprintf(minBuf, "%d", INT_MIN);
+ return UString(minBuf);
+ } else {
+ bool negative = false;
+ if (i < 0) {
+ negative = true;
+ i = -i;
+ }
+ while (i) {
+ *--p = (unsigned short)((i % 10) + '0');
+ i /= 10;
+ }
+ if (negative) {
+ *--p = '-';
+ }
+ }
+
+ return UString(p, static_cast<int>(end - p));
+}
+
+UString UString::from(unsigned int u)
+{
+ UChar buf[sizeof(u) * 3];
+ UChar *end = buf + sizeof(buf) / sizeof(UChar);
+ UChar *p = end;
+
+ if (u == 0) {
+ *--p = '0';
+ } else {
+ while (u) {
+ *--p = (unsigned short)((u % 10) + '0');
+ u /= 10;
+ }
+ }
+
+ return UString(p, static_cast<int>(end - p));
+}
+
+UString UString::from(long l)
+{
+ UChar buf[1 + sizeof(l) * 3];
+ UChar *end = buf + sizeof(buf) / sizeof(UChar);
+ UChar *p = end;
+
+ if (l == 0) {
+ *--p = '0';
+ } else if (l == LONG_MIN) {
+ char minBuf[1 + sizeof(l) * 3];
+ sprintf(minBuf, "%ld", LONG_MIN);
+ return UString(minBuf);
+ } else {
+ bool negative = false;
+ if (l < 0) {
+ negative = true;
+ l = -l;
+ }
+ while (l) {
+ *--p = (unsigned short)((l % 10) + '0');
+ l /= 10;
+ }
+ if (negative) {
+ *--p = '-';
+ }
+ }
+
+ return UString(p, static_cast<int>(end - p));
+}
+
+UString UString::from(double d)
+{
+ // avoid ever printing -NaN, in JS conceptually there is only one NaN value
+ if (isnan(d))
+ return "NaN";
+
+ char buf[80];
+ int decimalPoint;
+ int sign;
+
+ char *result = kjs_dtoa(d, 0, 0, &decimalPoint, &sign, NULL);
+ int length = static_cast<int>(strlen(result));
+
+ int i = 0;
+ if (sign) {
+ buf[i++] = '-';
+ }
+
+ if (decimalPoint <= 0 && decimalPoint > -6) {
+ buf[i++] = '0';
+ buf[i++] = '.';
+ for (int j = decimalPoint; j < 0; j++) {
+ buf[i++] = '0';
+ }
+ strcpy(buf + i, result);
+ } else if (decimalPoint <= 21 && decimalPoint > 0) {
+ if (length <= decimalPoint) {
+ strcpy(buf + i, result);
+ i += length;
+ for (int j = 0; j < decimalPoint - length; j++) {
+ buf[i++] = '0';
+ }
+ buf[i] = '\0';
+ } else {
+ strncpy(buf + i, result, decimalPoint);
+ i += decimalPoint;
+ buf[i++] = '.';
+ strcpy(buf + i, result + decimalPoint);
+ }
+ } else if (result[0] < '0' || result[0] > '9') {
+ strcpy(buf + i, result);
+ } else {
+ buf[i++] = result[0];
+ if (length > 1) {
+ buf[i++] = '.';
+ strcpy(buf + i, result + 1);
+ i += length - 1;
+ }
+
+ buf[i++] = 'e';
+ buf[i++] = (decimalPoint >= 0) ? '+' : '-';
+ // decimalPoint can't be more than 3 digits decimal given the
+ // nature of float representation
+ int exponential = decimalPoint - 1;
+ if (exponential < 0)
+ exponential = -exponential;
+ if (exponential >= 100)
+ buf[i++] = static_cast<char>('0' + exponential / 100);
+ if (exponential >= 10)
+ buf[i++] = static_cast<char>('0' + (exponential % 100) / 10);
+ buf[i++] = static_cast<char>('0' + exponential % 10);
+ buf[i++] = '\0';
+ }
+
+ kjs_freedtoa(result);
+
+ return UString(buf);
+}
+
+UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const
+{
+ if (rangeCount == 1 && separatorCount == 0) {
+ int thisSize = size();
+ int position = substringRanges[0].position;
+ int length = substringRanges[0].length;
+ if (position <= 0 && length >= thisSize)
+ return *this;
+ return UString::Rep::create(m_rep, max(0, position), min(thisSize, length));
+ }
+
+ int totalLength = 0;
+ for (int i = 0; i < rangeCount; i++)
+ totalLength += substringRanges[i].length;
+ for (int i = 0; i < separatorCount; i++)
+ totalLength += separators[i].size();
+
+ if (totalLength == 0)
+ return "";
+
+ UChar* buffer = allocChars(totalLength);
+ if (!buffer)
+ return null();
+
+ int maxCount = max(rangeCount, separatorCount);
+ int bufferPos = 0;
+ for (int i = 0; i < maxCount; i++) {
+ if (i < rangeCount) {
+ memcpy(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length * sizeof(UChar));
+ bufferPos += substringRanges[i].length;
+ }
+ if (i < separatorCount) {
+ memcpy(buffer + bufferPos, separators[i].data(), separators[i].size() * sizeof(UChar));
+ bufferPos += separators[i].size();
+ }
+ }
+
+ return UString::Rep::create(buffer, totalLength);
+}
+
+UString &UString::append(const UString &t)
+{
+ int thisSize = size();
+ int thisOffset = m_rep->offset;
+ int tSize = t.size();
+ int length = thisSize + tSize;
+
+ // possible cases:
+ if (thisSize == 0) {
+ // this is empty
+ *this = t;
+ } else if (tSize == 0) {
+ // t is empty
+ } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
+ // this is direct and has refcount of 1 (so we can just alter it directly)
+ expandCapacity(thisOffset + length);
+ if (data()) {
+ memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar));
+ m_rep->len = length;
+ m_rep->_hash = 0;
+ }
+ } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) {
+ // this reaches the end of the buffer - extend it if it's long enough to append to
+ expandCapacity(thisOffset + length);
+ if (data()) {
+ memcpy(const_cast<UChar*>(data() + thisSize), t.data(), tSize * sizeof(UChar));
+ m_rep = Rep::create(m_rep, 0, length);
+ }
+ } else {
+ // this is shared with someone using more capacity, gotta make a whole new string
+ size_t newCapacity = expandedSize(length, 0);
+ UChar* d = allocChars(newCapacity);
+ if (!d)
+ m_rep = &Rep::null;
+ else {
+ memcpy(d, data(), thisSize * sizeof(UChar));
+ memcpy(const_cast<UChar*>(d + thisSize), t.data(), tSize * sizeof(UChar));
+ m_rep = Rep::create(d, length);
+ m_rep->capacity = newCapacity;
+ }
+ }
+
+ return *this;
+}
+
+UString &UString::append(const char *t)
+{
+ int thisSize = size();
+ int thisOffset = m_rep->offset;
+ int tSize = static_cast<int>(strlen(t));
+ int length = thisSize + tSize;
+
+ // possible cases:
+ if (thisSize == 0) {
+ // this is empty
+ *this = t;
+ } else if (tSize == 0) {
+ // t is empty, we'll just return *this below.
+ } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
+ // this is direct and has refcount of 1 (so we can just alter it directly)
+ expandCapacity(thisOffset + length);
+ UChar *d = const_cast<UChar *>(data());
+ if (d) {
+ for (int i = 0; i < tSize; ++i)
+ d[thisSize + i] = t[i];
+ m_rep->len = length;
+ m_rep->_hash = 0;
+ }
+ } else if (thisOffset + thisSize == usedCapacity() && thisSize >= minShareSize) {
+ // this string reaches the end of the buffer - extend it
+ expandCapacity(thisOffset + length);
+ UChar *d = const_cast<UChar *>(data());
+ if (d) {
+ for (int i = 0; i < tSize; ++i)
+ d[thisSize + i] = t[i];
+ m_rep = Rep::create(m_rep, 0, length);
+ }
+ } else {
+ // this is shared with someone using more capacity, gotta make a whole new string
+ size_t newCapacity = expandedSize(length, 0);
+ UChar* d = allocChars(newCapacity);
+ if (!d)
+ m_rep = &Rep::null;
+ else {
+ memcpy(d, data(), thisSize * sizeof(UChar));
+ for (int i = 0; i < tSize; ++i)
+ d[thisSize + i] = t[i];
+ m_rep = Rep::create(d, length);
+ m_rep->capacity = newCapacity;
+ }
+ }
+
+ return *this;
+}
+
+UString &UString::append(unsigned short c)
+{
+ int thisOffset = m_rep->offset;
+ int length = size();
+
+ // possible cases:
+ if (length == 0) {
+ // this is empty - must make a new m_rep because we don't want to pollute the shared empty one
+ size_t newCapacity = expandedSize(1, 0);
+ UChar* d = allocChars(newCapacity);
+ if (!d)
+ m_rep = &Rep::null;
+ else {
+ d[0] = c;
+ m_rep = Rep::create(d, 1);
+ m_rep->capacity = newCapacity;
+ }
+ } else if (m_rep->baseIsSelf() && m_rep->rc == 1) {
+ // this is direct and has refcount of 1 (so we can just alter it directly)
+ expandCapacity(thisOffset + length + 1);
+ UChar *d = const_cast<UChar *>(data());
+ if (d) {
+ d[length] = c;
+ m_rep->len = length + 1;
+ m_rep->_hash = 0;
+ }
+ } else if (thisOffset + length == usedCapacity() && length >= minShareSize) {
+ // this reaches the end of the string - extend it and share
+ expandCapacity(thisOffset + length + 1);
+ UChar *d = const_cast<UChar *>(data());
+ if (d) {
+ d[length] = c;
+ m_rep = Rep::create(m_rep, 0, length + 1);
+ }
+ } else {
+ // this is shared with someone using more capacity, gotta make a whole new string
+ size_t newCapacity = expandedSize(length + 1, 0);
+ UChar* d = allocChars(newCapacity);
+ if (!d)
+ m_rep = &Rep::null;
+ else {
+ memcpy(d, data(), length * sizeof(UChar));
+ d[length] = c;
+ m_rep = Rep::create(d, length + 1);
+ m_rep->capacity = newCapacity;
+ }
+ }
+
+ return *this;
+}
+
+CString UString::cstring() const
+{
+ return ascii();
+}
+
+char *UString::ascii() const
+{
+ // Never make the buffer smaller than normalStatBufferSize.
+ // Thus we almost never need to reallocate.
+ int length = size();
+ int neededSize = length + 1;
+ if (neededSize < normalStatBufferSize) {
+ neededSize = normalStatBufferSize;
+ }
+ if (neededSize != statBufferSize) {
+ delete [] statBuffer;
+ statBuffer = new char [neededSize];
+ statBufferSize = neededSize;
+ }
+
+ const UChar *p = data();
+ char *q = statBuffer;
+ const UChar *limit = p + length;
+ while (p != limit) {
+ *q = static_cast<char>(p->uc);
+ ++p;
+ ++q;
+ }
+ *q = '\0';
+
+ return statBuffer;
+}
+
+UString &UString::operator=(const char *c)
+{
+ if (!c) {
+ m_rep = &Rep::null;
+ return *this;
+ }
+
+ if (!c[0]) {
+ m_rep = &Rep::empty;
+ return *this;
+ }
+
+ int l = static_cast<int>(strlen(c));
+ UChar *d;
+ if (m_rep->rc == 1 && l <= m_rep->capacity && m_rep->baseIsSelf() && m_rep->offset == 0 && m_rep->preCapacity == 0) {
+ d = m_rep->buf;
+ m_rep->_hash = 0;
+ m_rep->len = l;
+ } else {
+ d = allocChars(l);
+ if (!d) {
+ m_rep = &Rep::null;
+ return *this;
+ }
+ m_rep = Rep::create(d, l);
+ }
+ for (int i = 0; i < l; i++)
+ d[i].uc = c[i];
+
+ return *this;
+}
+
+bool UString::is8Bit() const
+{
+ const UChar *u = data();
+ const UChar *limit = u + size();
+ while (u < limit) {
+ if (u->uc > 0xFF)
+ return false;
+ ++u;
+ }
+
+ return true;
+}
+
+const UChar UString::operator[](int pos) const
+{
+ if (pos >= size())
+ return '\0';
+ return data()[pos];
+}
+
+double UString::toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const
+{
+ double d;
+
+ // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk
+ // after the number, so is8Bit is too strict a check.
+ if (!is8Bit())
+ return NaN;
+
+ const char *c = ascii();
+
+ // skip leading white space
+ while (isASCIISpace(*c))
+ c++;
+
+ // empty string ?
+ if (*c == '\0')
+ return tolerateEmptyString ? 0.0 : NaN;
+
+ // hex number ?
+ if (*c == '0' && (*(c+1) == 'x' || *(c+1) == 'X')) {
+ const char* firstDigitPosition = c + 2;
+ c++;
+ d = 0.0;
+ while (*(++c)) {
+ if (*c >= '0' && *c <= '9')
+ d = d * 16.0 + *c - '0';
+ else if ((*c >= 'A' && *c <= 'F') || (*c >= 'a' && *c <= 'f'))
+ d = d * 16.0 + (*c & 0xdf) - 'A' + 10.0;
+ else
+ break;
+ }
+
+ if (d >= mantissaOverflowLowerBound)
+ d = parseIntOverflow(firstDigitPosition, c - firstDigitPosition, 16);
+ } else {
+ // regular number ?
+ char *end;
+ d = kjs_strtod(c, &end);
+ if ((d != 0.0 || end != c) && d != Inf && d != -Inf) {
+ c = end;
+ } else {
+ double sign = 1.0;
+
+ if (*c == '+')
+ c++;
+ else if (*c == '-') {
+ sign = -1.0;
+ c++;
+ }
+
+ // We used strtod() to do the conversion. However, strtod() handles
+ // infinite values slightly differently than JavaScript in that it
+ // converts the string "inf" with any capitalization to infinity,
+ // whereas the ECMA spec requires that it be converted to NaN.
+
+ if (c[0] == 'I' && c[1] == 'n' && c[2] == 'f' && c[3] == 'i' && c[4] == 'n' && c[5] == 'i' && c[6] == 't' && c[7] == 'y') {
+ d = sign * Inf;
+ c += 8;
+ } else if ((d == Inf || d == -Inf) && *c != 'I' && *c != 'i')
+ c = end;
+ else
+ return NaN;
+ }
+ }
+
+ // allow trailing white space
+ while (isASCIISpace(*c))
+ c++;
+ // don't allow anything after - unless tolerant=true
+ if (!tolerateTrailingJunk && *c != '\0')
+ d = NaN;
+
+ return d;
+}
+
+double UString::toDouble(bool tolerateTrailingJunk) const
+{
+ return toDouble(tolerateTrailingJunk, true);
+}
+
+double UString::toDouble() const
+{
+ return toDouble(false, true);
+}
+
+uint32_t UString::toUInt32(bool *ok) const
+{
+ double d = toDouble();
+ bool b = true;
+
+ if (d != static_cast<uint32_t>(d)) {
+ b = false;
+ d = 0;
+ }
+
+ if (ok)
+ *ok = b;
+
+ return static_cast<uint32_t>(d);
+}
+
+uint32_t UString::toUInt32(bool *ok, bool tolerateEmptyString) const
+{
+ double d = toDouble(false, tolerateEmptyString);
+ bool b = true;
+
+ if (d != static_cast<uint32_t>(d)) {
+ b = false;
+ d = 0;
+ }
+
+ if (ok)
+ *ok = b;
+
+ return static_cast<uint32_t>(d);
+}
+
+uint32_t UString::toStrictUInt32(bool *ok) const
+{
+ if (ok)
+ *ok = false;
+
+ // Empty string is not OK.
+ int len = m_rep->len;
+ if (len == 0)
+ return 0;
+ const UChar *p = m_rep->data();
+ unsigned short c = p->unicode();
+
+ // If the first digit is 0, only 0 itself is OK.
+ if (c == '0') {
+ if (len == 1 && ok)
+ *ok = true;
+ return 0;
+ }
+
+ // Convert to UInt32, checking for overflow.
+ uint32_t i = 0;
+ while (1) {
+ // Process character, turning it into a digit.
+ if (c < '0' || c > '9')
+ return 0;
+ const unsigned d = c - '0';
+
+ // Multiply by 10, checking for overflow out of 32 bits.
+ if (i > 0xFFFFFFFFU / 10)
+ return 0;
+ i *= 10;
+
+ // Add in the digit, checking for overflow out of 32 bits.
+ const unsigned max = 0xFFFFFFFFU - d;
+ if (i > max)
+ return 0;
+ i += d;
+
+ // Handle end of string.
+ if (--len == 0) {
+ if (ok)
+ *ok = true;
+ return i;
+ }
+
+ // Get next character.
+ c = (++p)->unicode();
+ }
+}
+
+int UString::find(const UString &f, int pos) const
+{
+ int sz = size();
+ int fsz = f.size();
+ if (sz < fsz)
+ return -1;
+ if (pos < 0)
+ pos = 0;
+ if (fsz == 0)
+ return pos;
+ const UChar *end = data() + sz - fsz;
+ int fsizeminusone = (fsz - 1) * sizeof(UChar);
+ const UChar *fdata = f.data();
+ unsigned short fchar = fdata->uc;
+ ++fdata;
+ for (const UChar *c = data() + pos; c <= end; c++)
+ if (c->uc == fchar && !memcmp(c + 1, fdata, fsizeminusone))
+ return static_cast<int>(c - data());
+
+ return -1;
+}
+
+int UString::find(UChar ch, int pos) const
+{
+ if (pos < 0)
+ pos = 0;
+ const UChar *end = data() + size();
+ for (const UChar *c = data() + pos; c < end; c++)
+ if (*c == ch)
+ return static_cast<int>(c - data());
+
+ return -1;
+}
+
+int UString::rfind(const UString &f, int pos) const
+{
+ int sz = size();
+ int fsz = f.size();
+ if (sz < fsz)
+ return -1;
+ if (pos < 0)
+ pos = 0;
+ if (pos > sz - fsz)
+ pos = sz - fsz;
+ if (fsz == 0)
+ return pos;
+ int fsizeminusone = (fsz - 1) * sizeof(UChar);
+ const UChar *fdata = f.data();
+ for (const UChar *c = data() + pos; c >= data(); c--) {
+ if (*c == *fdata && !memcmp(c + 1, fdata + 1, fsizeminusone))
+ return static_cast<int>(c - data());
+ }
+
+ return -1;
+}
+
+int UString::rfind(UChar ch, int pos) const
+{
+ if (isEmpty())
+ return -1;
+ if (pos + 1 >= size())
+ pos = size() - 1;
+ for (const UChar *c = data() + pos; c >= data(); c--) {
+ if (*c == ch)
+ return static_cast<int>(c-data());
+ }
+
+ return -1;
+}
+
+UString UString::substr(int pos, int len) const
+{
+ int s = size();
+
+ if (pos < 0)
+ pos = 0;
+ else if (pos >= s)
+ pos = s;
+ if (len < 0)
+ len = s;
+ if (pos + len >= s)
+ len = s - pos;
+
+ if (pos == 0 && len == s)
+ return *this;
+
+ return UString(Rep::create(m_rep, pos, len));
+}
+
+bool operator==(const UString& s1, const UString& s2)
+{
+ if (s1.m_rep->len != s2.m_rep->len)
+ return false;
+
+ return (memcmp(s1.m_rep->data(), s2.m_rep->data(),
+ s1.m_rep->len * sizeof(UChar)) == 0);
+}
+
+bool operator==(const UString& s1, const char *s2)
+{
+ if (s2 == 0) {
+ return s1.isEmpty();
+ }
+
+ const UChar *u = s1.data();
+ const UChar *uend = u + s1.size();
+ while (u != uend && *s2) {
+ if (u->uc != (unsigned char)*s2)
+ return false;
+ s2++;
+ u++;
+ }
+
+ return u == uend && *s2 == 0;
+}
+
+bool operator<(const UString& s1, const UString& s2)
+{
+ const int l1 = s1.size();
+ const int l2 = s2.size();
+ const int lmin = l1 < l2 ? l1 : l2;
+ const UChar *c1 = s1.data();
+ const UChar *c2 = s2.data();
+ int l = 0;
+ while (l < lmin && *c1 == *c2) {
+ c1++;
+ c2++;
+ l++;
+ }
+ if (l < lmin)
+ return (c1->uc < c2->uc);
+
+ return (l1 < l2);
+}
+
+int compare(const UString& s1, const UString& s2)
+{
+ const int l1 = s1.size();
+ const int l2 = s2.size();
+ const int lmin = l1 < l2 ? l1 : l2;
+ const UChar *c1 = s1.data();
+ const UChar *c2 = s2.data();
+ int l = 0;
+ while (l < lmin && *c1 == *c2) {
+ c1++;
+ c2++;
+ l++;
+ }
+
+ if (l < lmin)
+ return (c1->uc > c2->uc) ? 1 : -1;
+
+ if (l1 == l2)
+ return 0;
+
+ return (l1 > l2) ? 1 : -1;
+}
+
+CString UString::UTF8String(bool strict) const
+{
+ // Allocate a buffer big enough to hold all the characters.
+ const int length = size();
+ Vector<char, 1024> buffer(length * 3);
+
+ // Convert to runs of 8-bit characters.
+ char* p = buffer.data();
+ const ::UChar* d = reinterpret_cast<const ::UChar*>(&data()->uc);
+ ConversionResult result = convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), strict);
+ if (result != conversionOK)
+ return CString();
+
+ return CString(buffer.data(), p - buffer.data());
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/ustring.h b/JavaScriptCore/kjs/ustring.h
new file mode 100644
index 0000000..7faa86a
--- /dev/null
+++ b/JavaScriptCore/kjs/ustring.h
@@ -0,0 +1,470 @@
+// -*- c-basic-offset: 2 -*-
+/*
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public License
+ * along with this library; see the file COPYING.LIB. If not, write to
+ * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA.
+ *
+ */
+
+#ifndef _KJS_USTRING_H_
+#define _KJS_USTRING_H_
+
+#include "JSLock.h"
+#include "collector.h"
+#include <stdint.h>
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/PassRefPtr.h>
+#include <wtf/RefPtr.h>
+#include <wtf/Vector.h>
+
+/* On some ARM platforms GCC won't pack structures by default so sizeof(UChar)
+ will end up being != 2 which causes crashes since the code depends on that. */
+#if COMPILER(GCC) && PLATFORM(FORCE_PACK)
+#define PACK_STRUCT __attribute__((packed))
+#else
+#define PACK_STRUCT
+#endif
+
+/**
+ * @internal
+ */
+namespace DOM {
+ class DOMString;
+ class AtomicString;
+}
+class KJScript;
+
+namespace KJS {
+
+ using WTF::PlacementNewAdoptType;
+ using WTF::PlacementNewAdopt;
+
+ class UString;
+
+ /**
+ * @short Unicode character.
+ *
+ * UChar represents a 16 bit Unicode character. It's internal data
+ * representation is compatible to XChar2b and QChar. It's therefore
+ * possible to exchange data with X and Qt with shallow copies.
+ */
+ struct UChar {
+ /**
+ * Construct a character with uninitialized value.
+ */
+ UChar();
+ /**
+ * Construct a character with the value denoted by the arguments.
+ * @param h higher byte
+ * @param l lower byte
+ */
+ UChar(unsigned char h , unsigned char l);
+ /**
+ * Construct a character with the given value.
+ * @param u 16 bit Unicode value
+ */
+ UChar(char u);
+ UChar(unsigned char u);
+ UChar(unsigned short u);
+ /**
+ * @return The higher byte of the character.
+ */
+ unsigned char high() const { return static_cast<unsigned char>(uc >> 8); }
+ /**
+ * @return The lower byte of the character.
+ */
+ unsigned char low() const { return static_cast<unsigned char>(uc); }
+ /**
+ * @return the 16 bit Unicode value of the character
+ */
+ unsigned short unicode() const { return uc; }
+
+ unsigned short uc;
+ } PACK_STRUCT;
+
+ inline UChar::UChar() { }
+ inline UChar::UChar(unsigned char h , unsigned char l) : uc(h << 8 | l) { }
+ inline UChar::UChar(char u) : uc((unsigned char)u) { }
+ inline UChar::UChar(unsigned char u) : uc(u) { }
+ inline UChar::UChar(unsigned short u) : uc(u) { }
+
+ /**
+ * @short 8 bit char based string class
+ */
+ class CString {
+ public:
+ CString() : data(0), length(0) { }
+ CString(const char *c);
+ CString(const char *c, size_t len);
+ CString(const CString &);
+
+ ~CString();
+
+ CString &append(const CString &);
+ CString &operator=(const char *c);
+ CString &operator=(const CString &);
+ CString &operator+=(const CString &c) { return append(c); }
+
+ size_t size() const { return length; }
+ const char *c_str() const { return data; }
+ private:
+ char *data;
+ size_t length;
+ };
+
+ /**
+ * @short Unicode string class
+ */
+ class UString {
+ friend bool operator==(const UString&, const UString&);
+
+ public:
+ /**
+ * @internal
+ */
+ struct Rep {
+
+ static PassRefPtr<Rep> create(UChar *d, int l);
+ static PassRefPtr<Rep> createCopying(const UChar *d, int l);
+ static PassRefPtr<Rep> create(PassRefPtr<Rep> base, int offset, int length);
+
+ void destroy();
+
+ bool baseIsSelf() const { return baseString == this; }
+ UChar* data() const { return baseString->buf + baseString->preCapacity + offset; }
+ int size() const { return len; }
+
+ unsigned hash() const { if (_hash == 0) _hash = computeHash(data(), len); return _hash; }
+ unsigned computedHash() const { ASSERT(_hash); return _hash; } // fast path for Identifiers
+
+ static unsigned computeHash(const UChar *, int length);
+ static unsigned computeHash(const char *);
+
+ Rep* ref() { ASSERT(JSLock::lockCount() > 0); ++rc; return this; }
+ ALWAYS_INLINE void deref() { ASSERT(JSLock::lockCount() > 0); if (--rc == 0) destroy(); }
+
+ // unshared data
+ int offset;
+ int len;
+ int rc;
+ mutable unsigned _hash;
+ bool isIdentifier;
+ UString::Rep* baseString;
+ size_t reportedCost;
+
+ // potentially shared data
+ UChar *buf;
+ int usedCapacity;
+ int capacity;
+ int usedPreCapacity;
+ int preCapacity;
+
+ static Rep null;
+ static Rep empty;
+ };
+
+ public:
+
+ /**
+ * Constructs a null string.
+ */
+ UString();
+ /**
+ * Constructs a string from a classical zero-terminated char string.
+ */
+ UString(const char *c);
+ /**
+ * Constructs a string from an array of Unicode characters of the specified
+ * length.
+ */
+ UString(const UChar *c, int length);
+ /**
+ * If copy is false the string data will be adopted.
+ * That means that the data will NOT be copied and the pointer will
+ * be deleted when the UString object is modified or destroyed.
+ * Behaviour defaults to a deep copy if copy is true.
+ */
+ UString(UChar *c, int length, bool copy);
+ /**
+ * Copy constructor. Makes a shallow copy only.
+ */
+ UString(const UString &s) : m_rep(s.m_rep) {}
+
+ UString(const Vector<UChar>& buffer);
+
+ /**
+ * Convenience declaration only ! You'll be on your own to write the
+ * implementation for a construction from DOM::DOMString.
+ *
+ * Note: feel free to contact me if you want to see a dummy header for
+ * your favorite FooString class here !
+ */
+ UString(const DOM::DOMString&);
+ /**
+ * Convenience declaration only ! See UString(const DOM::DOMString&).
+ */
+ UString(const DOM::AtomicString&);
+
+ /**
+ * Concatenation constructor. Makes operator+ more efficient.
+ */
+ UString(const UString &, const UString &);
+ /**
+ * Destructor.
+ */
+ ~UString() {}
+
+ // Special constructor for cases where we overwrite an object in place.
+ UString(PlacementNewAdoptType) : m_rep(PlacementNewAdopt) { }
+
+ /**
+ * Constructs a string from an int.
+ */
+ static UString from(int i);
+ /**
+ * Constructs a string from an unsigned int.
+ */
+ static UString from(unsigned int u);
+ /**
+ * Constructs a string from a long int.
+ */
+ static UString from(long u);
+ /**
+ * Constructs a string from a double.
+ */
+ static UString from(double d);
+
+ struct Range {
+ public:
+ Range(int pos, int len) : position(pos), length(len) {}
+ Range() {}
+ int position;
+ int length;
+ };
+
+ UString spliceSubstringsWithSeparators(const Range *substringRanges, int rangeCount, const UString *separators, int separatorCount) const;
+
+ /**
+ * Append another string.
+ */
+ UString &append(const UString &);
+ UString &append(const char *);
+ UString &append(unsigned short);
+ UString &append(char c) { return append(static_cast<unsigned short>(static_cast<unsigned char>(c))); }
+ UString &append(UChar c) { return append(c.uc); }
+
+ /**
+ * @return The string converted to the 8-bit string type CString().
+ * This method is not Unicode safe and shouldn't be used unless the string
+ * is known to be ASCII.
+ */
+ CString cstring() const;
+ /**
+ * Convert the Unicode string to plain ASCII chars chopping of any higher
+ * bytes. This method should only be used for *debugging* purposes as it
+ * is neither Unicode safe nor free from side effects. In order not to
+ * waste any memory the char buffer is static and *shared* by all UString
+ * instances.
+ */
+ char *ascii() const;
+
+ /**
+ * Convert the string to UTF-8, assuming it is UTF-16 encoded.
+ * In non-strict mode, this function is tolerant of badly formed UTF-16, it
+ * can create UTF-8 strings that are invalid because they have characters in
+ * the range U+D800-U+DDFF, U+FFFE, or U+FFFF, but the UTF-8 string is
+ * guaranteed to be otherwise valid.
+ * In strict mode, error is returned as null CString.
+ */
+ CString UTF8String(bool strict = false) const;
+
+ /**
+ * @see UString(const DOM::DOMString&).
+ */
+ DOM::DOMString domString() const;
+
+ /**
+ * Assignment operator.
+ */
+ UString &operator=(const char *c);
+ /**
+ * Appends the specified string.
+ */
+ UString &operator+=(const UString &s) { return append(s); }
+ UString &operator+=(const char *s) { return append(s); }
+
+ /**
+ * @return A pointer to the internal Unicode data.
+ */
+ const UChar* data() const { return m_rep->data(); }
+ /**
+ * @return True if null.
+ */
+ bool isNull() const { return (m_rep == &Rep::null); }
+ /**
+ * @return True if null or zero length.
+ */
+ bool isEmpty() const { return (!m_rep->len); }
+ /**
+ * Use this if you want to make sure that this string is a plain ASCII
+ * string. For example, if you don't want to lose any information when
+ * using cstring() or ascii().
+ *
+ * @return True if the string doesn't contain any non-ASCII characters.
+ */
+ bool is8Bit() const;
+ /**
+ * @return The length of the string.
+ */
+ int size() const { return m_rep->size(); }
+ /**
+ * Const character at specified position.
+ */
+ const UChar operator[](int pos) const;
+
+ /**
+ * Attempts an conversion to a number. Apart from floating point numbers,
+ * the algorithm will recognize hexadecimal representations (as
+ * indicated by a 0x or 0X prefix) and +/- Infinity.
+ * Returns NaN if the conversion failed.
+ * @param tolerateTrailingJunk if true, toDouble can tolerate garbage after the number.
+ * @param tolerateEmptyString if false, toDouble will turn an empty string into NaN rather than 0.
+ */
+ double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const;
+ double toDouble(bool tolerateTrailingJunk) const;
+ double toDouble() const;
+
+ /**
+ * Attempts an conversion to a 32-bit integer. ok will be set
+ * according to the success.
+ * @param tolerateEmptyString if false, toUInt32 will return false for *ok for an empty string.
+ */
+ uint32_t toUInt32(bool *ok = 0) const;
+ uint32_t toUInt32(bool *ok, bool tolerateEmptyString) const;
+ uint32_t toStrictUInt32(bool *ok = 0) const;
+
+ /**
+ * Attempts an conversion to an array index. The "ok" boolean will be set
+ * to true if it is a valid array index according to the rule from
+ * ECMA 15.2 about what an array index is. It must exactly match the string
+ * form of an unsigned integer, and be less than 2^32 - 1.
+ */
+ unsigned toArrayIndex(bool *ok = 0) const;
+
+ /**
+ * @return Position of first occurrence of f starting at position pos.
+ * -1 if the search was not successful.
+ */
+ int find(const UString &f, int pos = 0) const;
+ int find(UChar, int pos = 0) const;
+ /**
+ * @return Position of first occurrence of f searching backwards from
+ * position pos.
+ * -1 if the search was not successful.
+ */
+ int rfind(const UString &f, int pos) const;
+ int rfind(UChar, int pos) const;
+ /**
+ * @return The sub string starting at position pos and length len.
+ */
+ UString substr(int pos = 0, int len = -1) const;
+ /**
+ * Static instance of a null string.
+ */
+ static const UString &null();
+
+ Rep* rep() const { return m_rep.get(); }
+ UString(PassRefPtr<Rep> r) : m_rep(r) { ASSERT(m_rep); }
+
+ size_t cost() const;
+
+ private:
+ size_t expandedSize(size_t size, size_t otherSize) const;
+ int usedCapacity() const;
+ int usedPreCapacity() const;
+ void expandCapacity(int requiredLength);
+ void expandPreCapacity(int requiredPreCap);
+
+ RefPtr<Rep> m_rep;
+ };
+
+ inline bool operator==(const UChar &c1, const UChar &c2) {
+ return (c1.uc == c2.uc);
+ }
+ bool operator==(const UString& s1, const UString& s2);
+ inline bool operator!=(const UString& s1, const UString& s2) {
+ return !KJS::operator==(s1, 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 !KJS::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 !KJS::operator==(s1, s2);
+ }
+ bool operator==(const CString& s1, const CString& s2);
+ inline UString operator+(const UString& s1, const UString& s2) {
+ return UString(s1, s2);
+ }
+
+ int compare(const UString &, const UString &);
+
+inline UString::UString()
+ : m_rep(&Rep::null)
+{
+}
+
+// Rule from ECMA 15.2 about what an array index is.
+// Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
+inline unsigned UString::toArrayIndex(bool *ok) const
+{
+ unsigned i = toStrictUInt32(ok);
+ if (ok && i >= 0xFFFFFFFFU)
+ *ok = false;
+ return i;
+}
+
+// We'd rather not do shared substring append for small strings, since
+// this runs too much risk of a tiny initial string holding down a
+// huge buffer.
+// FIXME: this should be size_t but that would cause warnings until we
+// fix UString sizes to be size_t instead of int
+static const int minShareSize = Collector::minExtraCostSize / sizeof(UChar);
+
+inline size_t UString::cost() const
+{
+ size_t capacity = (m_rep->baseString->capacity + m_rep->baseString->preCapacity) * sizeof(UChar);
+ size_t reportedCost = m_rep->baseString->reportedCost;
+ ASSERT(capacity >= reportedCost);
+
+ size_t capacityDelta = capacity - reportedCost;
+
+ if (capacityDelta < static_cast<size_t>(minShareSize))
+ return 0;
+
+ m_rep->baseString->reportedCost = capacity;
+ return capacityDelta;
+}
+
+} // namespace
+
+#endif
diff --git a/JavaScriptCore/kjs/value.cpp b/JavaScriptCore/kjs/value.cpp
new file mode 100644
index 0000000..55da40b
--- /dev/null
+++ b/JavaScriptCore/kjs/value.cpp
@@ -0,0 +1,232 @@
+/*
+ * 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 "value.h"
+
+#include "error_object.h"
+#include "nodes.h"
+#include <stdio.h>
+#include <string.h>
+#include <wtf/MathExtras.h>
+
+namespace KJS {
+
+#if defined NAN && defined INFINITY
+
+extern const double NaN = NAN;
+extern const double Inf = INFINITY;
+
+#else // !(defined NAN && defined INFINITY)
+
+// The trick is to define the NaN and Inf globals with a different type than the declaration.
+// This trick works because the mangled name of the globals does not include the type, although
+// I'm not sure that's guaranteed. There could be alignment issues with this, since arrays of
+// characters don't necessarily need the same alignment doubles do, but for now it seems to work.
+// It would be good to figure out a 100% clean way that still avoids code that runs at init time.
+
+// Note, we have to use union to ensure alignment. Otherwise, NaN_Bytes can start anywhere,
+// while NaN_double has to be 4-byte aligned for 32-bits.
+// With -fstrict-aliasing enabled, unions are the only safe way to do type masquerading.
+
+static const union {
+ struct {
+ unsigned char NaN_Bytes[8];
+ unsigned char Inf_Bytes[8];
+ } bytes;
+
+ struct {
+ double NaN_Double;
+ double Inf_Double;
+ } doubles;
+
+} NaNInf = { {
+#if PLATFORM(BIG_ENDIAN)
+ { 0x7f, 0xf8, 0, 0, 0, 0, 0, 0 },
+ { 0x7f, 0xf0, 0, 0, 0, 0, 0, 0 }
+#elif PLATFORM(MIDDLE_ENDIAN)
+ { 0, 0, 0xf8, 0x7f, 0, 0, 0, 0 },
+ { 0, 0, 0xf0, 0x7f, 0, 0, 0, 0 }
+#else
+ { 0, 0, 0, 0, 0, 0, 0xf8, 0x7f },
+ { 0, 0, 0, 0, 0, 0, 0xf0, 0x7f }
+#endif
+} } ;
+
+extern const double NaN = NaNInf.doubles.NaN_Double;
+extern const double Inf = NaNInf.doubles.Inf_Double;
+
+#endif // !(defined NAN && defined INFINITY)
+
+static const double D16 = 65536.0;
+static const double D32 = 4294967296.0;
+
+void *JSCell::operator new(size_t size)
+{
+ return Collector::allocate(size);
+}
+
+bool JSCell::getUInt32(uint32_t&) const
+{
+ return false;
+}
+
+bool JSCell::getTruncatedInt32(int32_t&) const
+{
+ return false;
+}
+
+bool JSCell::getTruncatedUInt32(uint32_t&) const
+{
+ return false;
+}
+
+// ECMA 9.4
+double JSValue::toInteger(ExecState *exec) const
+{
+ int32_t i;
+ if (getTruncatedInt32(i))
+ return i;
+ double d = toNumber(exec);
+ return isnan(d) ? 0.0 : trunc(d);
+}
+
+double JSValue::toIntegerPreserveNaN(ExecState *exec) const
+{
+ int32_t i;
+ if (getTruncatedInt32(i))
+ return i;
+ return trunc(toNumber(exec));
+}
+
+int32_t JSValue::toInt32SlowCase(double d, bool& ok)
+{
+ ok = true;
+
+ if (d >= -D32 / 2 && d < D32 / 2)
+ return static_cast<int32_t>(d);
+
+ if (isnan(d) || isinf(d)) {
+ ok = false;
+ return 0;
+ }
+
+ double d32 = fmod(trunc(d), D32);
+ if (d32 >= D32 / 2)
+ d32 -= D32;
+ else if (d32 < -D32 / 2)
+ d32 += D32;
+ return static_cast<int32_t>(d32);
+}
+
+int32_t JSValue::toInt32SlowCase(ExecState* exec, bool& ok) const
+{
+ return JSValue::toInt32SlowCase(toNumber(exec), ok);
+}
+
+uint32_t JSValue::toUInt32SlowCase(double d, bool& ok)
+{
+ ok = true;
+
+ if (d >= 0.0 && d < D32)
+ return static_cast<uint32_t>(d);
+
+ if (isnan(d) || isinf(d)) {
+ ok = false;
+ return 0;
+ }
+
+ double d32 = fmod(trunc(d), D32);
+ if (d32 < 0)
+ d32 += D32;
+ return static_cast<uint32_t>(d32);
+}
+
+uint32_t JSValue::toUInt32SlowCase(ExecState* exec, bool& ok) const
+{
+ return JSValue::toUInt32SlowCase(toNumber(exec), ok);
+}
+
+float JSValue::toFloat(ExecState* exec) const
+{
+ return static_cast<float>(toNumber(exec));
+}
+
+bool JSCell::getNumber(double &numericValue) const
+{
+ if (!isNumber())
+ return false;
+ numericValue = static_cast<const NumberImp *>(this)->value();
+ return true;
+}
+
+double JSCell::getNumber() const
+{
+ return isNumber() ? static_cast<const NumberImp *>(this)->value() : NaN;
+}
+
+bool JSCell::getString(UString &stringValue) const
+{
+ if (!isString())
+ return false;
+ stringValue = static_cast<const StringImp *>(this)->value();
+ return true;
+}
+
+UString JSCell::getString() const
+{
+ return isString() ? static_cast<const StringImp *>(this)->value() : UString();
+}
+
+JSObject *JSCell::getObject()
+{
+ return isObject() ? static_cast<JSObject *>(this) : 0;
+}
+
+const JSObject *JSCell::getObject() const
+{
+ return isObject() ? static_cast<const JSObject *>(this) : 0;
+}
+
+JSCell* jsString(const char* s)
+{
+ return new StringImp(s ? s : "");
+}
+
+JSCell* jsString(const UString& s)
+{
+ return s.isNull() ? new StringImp("") : new StringImp(s);
+}
+
+JSCell* jsOwnedString(const UString& s)
+{
+ return s.isNull() ? new StringImp("", StringImp::HasOtherOwner) : new StringImp(s, StringImp::HasOtherOwner);
+}
+
+// This method includes a PIC branch to set up the NumberImp's vtable, so we quarantine
+// it in a separate function to keep the normal case speedy.
+JSValue *jsNumberCell(double d)
+{
+ return new NumberImp(d);
+}
+
+} // namespace KJS
diff --git a/JavaScriptCore/kjs/value.h b/JavaScriptCore/kjs/value.h
new file mode 100644
index 0000000..5ebb575
--- /dev/null
+++ b/JavaScriptCore/kjs/value.h
@@ -0,0 +1,523 @@
+/*
+ * Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
+ * Copyright (C) 2001 Peter Kelly (pmk@post.com)
+ * Copyright (C) 2003, 2004, 2005, 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 KJS_VALUE_H
+#define KJS_VALUE_H
+
+#include "JSImmediate.h"
+#include "collector.h"
+#include "ustring.h"
+#include <stddef.h> // for size_t
+
+namespace KJS {
+
+class ExecState;
+class JSObject;
+class JSCell;
+
+struct ClassInfo;
+
+/**
+ * JSValue is the base type for all primitives (Undefined, Null, Boolean,
+ * String, Number) and objects in ECMAScript.
+ *
+ * Note: you should never inherit from JSValue as it is for primitive types
+ * only (all of which are provided internally by KJS). Instead, inherit from
+ * JSObject.
+ */
+class JSValue : Noncopyable {
+ friend class JSCell; // so it can derive from this class
+ friend class Collector; // so it can call asCell()
+
+private:
+ JSValue();
+ virtual ~JSValue();
+
+public:
+ // Querying the type.
+ JSType type() const;
+ bool isUndefined() const;
+ bool isNull() const;
+ bool isUndefinedOrNull() const;
+ bool isBoolean() const;
+ bool isNumber() const;
+ bool isString() const;
+ bool isObject() const;
+ bool isObject(const ClassInfo *) const;
+
+ // Extracting the value.
+ bool getBoolean(bool&) const;
+ bool getBoolean() const; // false if not a boolean
+ bool getNumber(double&) const;
+ double getNumber() const; // NaN if not a number
+ bool getString(UString&) const;
+ UString getString() const; // null string if not a string
+ JSObject *getObject(); // NULL if not an object
+ const JSObject *getObject() const; // NULL if not an object
+
+ // Extracting integer values.
+ bool getUInt32(uint32_t&) const;
+ bool getTruncatedInt32(int32_t&) const;
+ bool getTruncatedUInt32(uint32_t&) const;
+
+ // Basic conversions.
+ JSValue* toPrimitive(ExecState* exec, JSType preferredType = UnspecifiedType) const;
+ bool getPrimitiveNumber(ExecState* exec, double& number, JSValue*& value);
+
+ bool toBoolean(ExecState *exec) const;
+ double toNumber(ExecState *exec) const;
+ JSValue* toJSNumber(ExecState*) const; // Fast path for when you expect that the value is an immediate number.
+ UString toString(ExecState *exec) const;
+ JSObject *toObject(ExecState *exec) const;
+
+ // Integer conversions.
+ double toInteger(ExecState*) const;
+ double toIntegerPreserveNaN(ExecState*) const;
+ int32_t toInt32(ExecState*) const;
+ int32_t toInt32(ExecState*, bool& ok) const;
+ uint32_t toUInt32(ExecState*) const;
+ uint32_t toUInt32(ExecState*, bool& ok) const;
+
+ // These are identical logic to above, and faster than jsNumber(number)->toInt32(exec)
+ static int32_t toInt32(double);
+ static int32_t toUInt32(double);
+
+ // Floating point conversions.
+ float toFloat(ExecState*) const;
+
+ // Garbage collection.
+ void mark();
+ bool marked() const;
+
+ static int32_t toInt32SlowCase(double, bool& ok);
+ static uint32_t toUInt32SlowCase(double, bool& ok);
+
+private:
+ int32_t toInt32SlowCase(ExecState*, bool& ok) const;
+ uint32_t toUInt32SlowCase(ExecState*, bool& ok) const;
+
+ // Implementation details.
+ JSCell *asCell();
+ const JSCell *asCell() const;
+
+ // Give a compile time error if we try to copy one of these.
+ JSValue(const JSValue&);
+ JSValue& operator=(const JSValue&);
+};
+
+class JSCell : public JSValue {
+ friend class Collector;
+ friend class NumberImp;
+ friend class StringImp;
+ friend class JSObject;
+ friend class GetterSetterImp;
+private:
+ JSCell();
+ virtual ~JSCell();
+public:
+ // Querying the type.
+ virtual JSType type() const = 0;
+ bool isNumber() const;
+ bool isString() const;
+ bool isObject() const;
+ bool isObject(const ClassInfo *) const;
+
+ // Extracting the value.
+ bool getNumber(double&) const;
+ double getNumber() const; // NaN if not a number
+ bool getString(UString&) const;
+ UString getString() const; // null string if not a string
+ JSObject *getObject(); // NULL if not an object
+ const JSObject *getObject() const; // NULL if not an object
+
+ // Extracting integer values.
+ virtual bool getUInt32(uint32_t&) const;
+ virtual bool getTruncatedInt32(int32_t&) const;
+ virtual bool getTruncatedUInt32(uint32_t&) const;
+
+ // Basic conversions.
+ virtual JSValue *toPrimitive(ExecState *exec, JSType preferredType = UnspecifiedType) const = 0;
+ virtual bool getPrimitiveNumber(ExecState* exec, double& number, JSValue*& value) = 0;
+ virtual bool toBoolean(ExecState *exec) const = 0;
+ virtual double toNumber(ExecState *exec) const = 0;
+ virtual UString toString(ExecState *exec) const = 0;
+ virtual JSObject *toObject(ExecState *exec) const = 0;
+
+ // Garbage collection.
+ void *operator new(size_t);
+ virtual void mark();
+ bool marked() const;
+};
+
+JSValue *jsNumberCell(double);
+
+JSCell *jsString(const UString&); // returns empty string if passed null string
+JSCell *jsString(const char* = ""); // returns empty string if passed 0
+
+// 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
+JSCell *jsOwnedString(const UString&);
+
+extern const double NaN;
+extern const double Inf;
+
+inline JSValue *jsUndefined()
+{
+ return JSImmediate::undefinedImmediate();
+}
+
+inline JSValue *jsNull()
+{
+ return JSImmediate::nullImmediate();
+}
+
+inline JSValue *jsNaN()
+{
+ static const union {
+ uint64_t bits;
+ double d;
+ } nan = { 0x7ff80000ULL << 32 };
+ return jsNumberCell(nan.d);
+}
+
+inline JSValue *jsBoolean(bool b)
+{
+ return b ? JSImmediate::trueImmediate() : JSImmediate::falseImmediate();
+}
+
+ALWAYS_INLINE JSValue* jsNumber(double d)
+{
+ JSValue* v = JSImmediate::from(d);
+ return v ? v : jsNumberCell(d);
+}
+
+ALWAYS_INLINE JSValue* jsNumber(int i)
+{
+ JSValue* v = JSImmediate::from(i);
+ return v ? v : jsNumberCell(i);
+}
+
+ALWAYS_INLINE JSValue* jsNumber(unsigned i)
+{
+ JSValue* v = JSImmediate::from(i);
+ return v ? v : jsNumberCell(i);
+}
+
+ALWAYS_INLINE JSValue* jsNumber(long i)
+{
+ JSValue* v = JSImmediate::from(i);
+ return v ? v : jsNumberCell(i);
+}
+
+ALWAYS_INLINE JSValue* jsNumber(unsigned long i)
+{
+ JSValue* v = JSImmediate::from(i);
+ return v ? v : jsNumberCell(i);
+}
+
+ALWAYS_INLINE JSValue* jsNumber(long long i)
+{
+ JSValue* v = JSImmediate::from(i);
+ return v ? v : jsNumberCell(static_cast<double>(i));
+}
+
+ALWAYS_INLINE JSValue* jsNumber(unsigned long long i)
+{
+ JSValue* v = JSImmediate::from(i);
+ return v ? v : jsNumberCell(static_cast<double>(i));
+}
+
+ALWAYS_INLINE JSValue* jsNumberFromAnd(ExecState *exec, JSValue* v1, JSValue* v2)
+{
+ if (JSImmediate::areBothImmediateNumbers(v1, v2))
+ return JSImmediate::andImmediateNumbers(v1, v2);
+ return jsNumber(v1->toInt32(exec) & v2->toInt32(exec));
+}
+
+inline JSValue::JSValue()
+{
+}
+
+inline JSValue::~JSValue()
+{
+}
+
+inline JSCell::JSCell()
+{
+}
+
+inline JSCell::~JSCell()
+{
+}
+
+inline bool JSCell::isNumber() const
+{
+ return type() == NumberType;
+}
+
+inline bool JSCell::isString() const
+{
+ return type() == StringType;
+}
+
+inline bool JSCell::isObject() const
+{
+ return type() == ObjectType;
+}
+
+inline bool JSCell::marked() const
+{
+ return Collector::isCellMarked(this);
+}
+
+inline void JSCell::mark()
+{
+ return Collector::markCell(this);
+}
+
+ALWAYS_INLINE JSCell* JSValue::asCell()
+{
+ ASSERT(!JSImmediate::isImmediate(this));
+ return static_cast<JSCell*>(this);
+}
+
+ALWAYS_INLINE const JSCell* JSValue::asCell() const
+{
+ ASSERT(!JSImmediate::isImmediate(this));
+ return static_cast<const JSCell*>(this);
+}
+
+inline bool JSValue::isUndefined() const
+{
+ return this == jsUndefined();
+}
+
+inline bool JSValue::isNull() const
+{
+ return this == jsNull();
+}
+
+inline bool JSValue::isUndefinedOrNull() const
+{
+ return JSImmediate::isUndefinedOrNull(this);
+}
+
+inline bool JSValue::isBoolean() const
+{
+ return JSImmediate::isBoolean(this);
+}
+
+inline bool JSValue::isNumber() const
+{
+ return JSImmediate::isNumber(this) || (!JSImmediate::isImmediate(this) && asCell()->isNumber());
+}
+
+inline bool JSValue::isString() const
+{
+ return !JSImmediate::isImmediate(this) && asCell()->isString();
+}
+
+inline bool JSValue::isObject() const
+{
+ return !JSImmediate::isImmediate(this) && asCell()->isObject();
+}
+
+inline bool JSValue::getBoolean(bool& v) const
+{
+ if (JSImmediate::isBoolean(this)) {
+ v = JSImmediate::toBoolean(this);
+ return true;
+ }
+
+ return false;
+}
+
+inline bool JSValue::getBoolean() const
+{
+ return JSImmediate::isBoolean(this) ? JSImmediate::toBoolean(this) : false;
+}
+
+inline bool JSValue::getNumber(double& v) const
+{
+ if (JSImmediate::isImmediate(this)) {
+ v = JSImmediate::toDouble(this);
+ return true;
+ }
+ return asCell()->getNumber(v);
+}
+
+inline double JSValue::getNumber() const
+{
+ return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->getNumber();
+}
+
+inline bool JSValue::getString(UString& s) const
+{
+ return !JSImmediate::isImmediate(this) && asCell()->getString(s);
+}
+
+inline UString JSValue::getString() const
+{
+ return JSImmediate::isImmediate(this) ? UString() : asCell()->getString();
+}
+
+inline JSObject *JSValue::getObject()
+{
+ return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
+}
+
+inline const JSObject *JSValue::getObject() const
+{
+ return JSImmediate::isImmediate(this) ? 0 : asCell()->getObject();
+}
+
+ALWAYS_INLINE bool JSValue::getUInt32(uint32_t& v) const
+{
+ return JSImmediate::isImmediate(this) ? JSImmediate::getUInt32(this, v) : asCell()->getUInt32(v);
+}
+
+ALWAYS_INLINE bool JSValue::getTruncatedInt32(int32_t& v) const
+{
+ return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedInt32(this, v) : asCell()->getTruncatedInt32(v);
+}
+
+inline bool JSValue::getTruncatedUInt32(uint32_t& v) const
+{
+ return JSImmediate::isImmediate(this) ? JSImmediate::getTruncatedUInt32(this, v) : asCell()->getTruncatedUInt32(v);
+}
+
+inline void JSValue::mark()
+{
+ ASSERT(!JSImmediate::isImmediate(this)); // callers should check !marked() before calling mark()
+ asCell()->mark();
+}
+
+inline bool JSValue::marked() const
+{
+ return JSImmediate::isImmediate(this) || asCell()->marked();
+}
+
+inline JSType JSValue::type() const
+{
+ return JSImmediate::isImmediate(this) ? JSImmediate::type(this) : asCell()->type();
+}
+
+inline JSValue* JSValue::toPrimitive(ExecState* exec, JSType preferredType) const
+{
+ return JSImmediate::isImmediate(this) ? const_cast<JSValue*>(this) : asCell()->toPrimitive(exec, preferredType);
+}
+
+inline bool JSValue::getPrimitiveNumber(ExecState* exec, double& number, JSValue*& value)
+{
+ if (JSImmediate::isImmediate(this)) {
+ number = JSImmediate::toDouble(this);
+ value = this;
+ return true;
+ }
+ return asCell()->getPrimitiveNumber(exec, number, value);
+}
+
+inline bool JSValue::toBoolean(ExecState *exec) const
+{
+ return JSImmediate::isImmediate(this) ? JSImmediate::toBoolean(this) : asCell()->toBoolean(exec);
+}
+
+ALWAYS_INLINE double JSValue::toNumber(ExecState *exec) const
+{
+ return JSImmediate::isImmediate(this) ? JSImmediate::toDouble(this) : asCell()->toNumber(exec);
+}
+
+ALWAYS_INLINE JSValue* JSValue::toJSNumber(ExecState* exec) const
+{
+ return JSImmediate::isNumber(this) ? const_cast<JSValue*>(this) : jsNumber(this->toNumber(exec));
+}
+
+inline UString JSValue::toString(ExecState *exec) const
+{
+ return JSImmediate::isImmediate(this) ? JSImmediate::toString(this) : asCell()->toString(exec);
+}
+
+inline JSObject* JSValue::toObject(ExecState* exec) const
+{
+ return JSImmediate::isImmediate(this) ? JSImmediate::toObject(this, exec) : asCell()->toObject(exec);
+}
+
+ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const
+{
+ int32_t i;
+ if (getTruncatedInt32(i))
+ return i;
+ bool ok;
+ return toInt32SlowCase(exec, ok);
+}
+
+inline uint32_t JSValue::toUInt32(ExecState* exec) const
+{
+ uint32_t i;
+ if (getTruncatedUInt32(i))
+ return i;
+ bool ok;
+ return toUInt32SlowCase(exec, ok);
+}
+
+inline int32_t JSValue::toInt32(double val)
+{
+ if (!(val >= -2147483648.0 && val < 2147483648.0)) {
+ bool ignored;
+ return toInt32SlowCase(val, ignored);
+ }
+ return static_cast<int32_t>(val);
+}
+
+inline int32_t JSValue::toUInt32(double val)
+{
+ if (!(val >= 0.0 && val < 4294967296.0)) {
+ bool ignored;
+ return toUInt32SlowCase(val, ignored);
+ }
+ return static_cast<uint32_t>(val);
+}
+
+inline int32_t JSValue::toInt32(ExecState* exec, bool& ok) const
+{
+ int32_t i;
+ if (getTruncatedInt32(i)) {
+ ok = true;
+ return i;
+ }
+ return toInt32SlowCase(exec, ok);
+}
+
+inline uint32_t JSValue::toUInt32(ExecState* exec, bool& ok) const
+{
+ uint32_t i;
+ if (getTruncatedUInt32(i)) {
+ ok = true;
+ return i;
+ }
+ return toUInt32SlowCase(exec, ok);
+}
+
+} // namespace
+
+#endif // KJS_VALUE_H