summaryrefslogtreecommitdiffstats
path: root/JavaScriptCore/kjs
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2008-12-17 18:05:15 -0800
commit1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353 (patch)
tree4457a7306ea5acb43fe05bfe0973b1f7faf97ba2 /JavaScriptCore/kjs
parent9364f22aed35e1a1e9d07c121510f80be3ab0502 (diff)
downloadexternal_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.zip
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.gz
external_webkit-1cbdecfa9fc428ac2d8aca0fa91c9580b3d57353.tar.bz2
Code drop from //branches/cupcake/...@124589
Diffstat (limited to 'JavaScriptCore/kjs')
-rw-r--r--JavaScriptCore/kjs/Activation.h99
-rw-r--r--JavaScriptCore/kjs/AllInOneFile.cpp73
-rw-r--r--JavaScriptCore/kjs/CollectorHeapIntrospector.cpp94
-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.h234
-rw-r--r--JavaScriptCore/kjs/JSGlobalObject.cpp621
-rw-r--r--JavaScriptCore/kjs/JSGlobalObject.h269
-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.h121
-rw-r--r--JavaScriptCore/kjs/JSWrapperObject.cpp34
-rw-r--r--JavaScriptCore/kjs/JSWrapperObject.h84
-rw-r--r--JavaScriptCore/kjs/LabelScope.h92
-rw-r--r--JavaScriptCore/kjs/LabelStack.h84
-rw-r--r--JavaScriptCore/kjs/LocalStorage.h56
-rw-r--r--JavaScriptCore/kjs/NodeInfo.h47
-rw-r--r--JavaScriptCore/kjs/Parser.cpp66
-rw-r--r--JavaScriptCore/kjs/Parser.h78
-rw-r--r--JavaScriptCore/kjs/PropertyNameArray.cpp43
-rw-r--r--JavaScriptCore/kjs/PropertyNameArray.h56
-rw-r--r--JavaScriptCore/kjs/ResultType.h169
-rw-r--r--JavaScriptCore/kjs/SavedBuiltins.h94
-rw-r--r--JavaScriptCore/kjs/Shell.cpp501
-rw-r--r--JavaScriptCore/kjs/SourceCode.h90
-rw-r--r--JavaScriptCore/kjs/SourceProvider.h (renamed from JavaScriptCore/kjs/SymbolTable.h)65
-rw-r--r--JavaScriptCore/kjs/TypeInfo.h63
-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.cpp1139
-rw-r--r--JavaScriptCore/kjs/collector.h394
-rw-r--r--JavaScriptCore/kjs/completion.h52
-rw-r--r--JavaScriptCore/kjs/config.h52
-rwxr-xr-xJavaScriptCore/kjs/create_hash_table210
-rw-r--r--JavaScriptCore/kjs/date_object.cpp1615
-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.cpp4983
-rw-r--r--JavaScriptCore/kjs/dtoa.h27
-rw-r--r--JavaScriptCore/kjs/error_object.cpp153
-rw-r--r--JavaScriptCore/kjs/error_object.h77
-rw-r--r--JavaScriptCore/kjs/function.cpp885
-rw-r--r--JavaScriptCore/kjs/function.h161
-rw-r--r--JavaScriptCore/kjs/function_object.cpp244
-rw-r--r--JavaScriptCore/kjs/function_object.h61
-rw-r--r--JavaScriptCore/kjs/grammar.y1064
-rw-r--r--JavaScriptCore/kjs/identifier.cpp206
-rw-r--r--JavaScriptCore/kjs/identifier.h90
-rw-r--r--JavaScriptCore/kjs/internal.cpp302
-rw-r--r--JavaScriptCore/kjs/internal.h122
-rw-r--r--JavaScriptCore/kjs/interpreter.cpp135
-rw-r--r--JavaScriptCore/kjs/interpreter.h25
-rw-r--r--JavaScriptCore/kjs/jsc.pro35
-rw-r--r--JavaScriptCore/kjs/lexer.cpp1411
-rw-r--r--JavaScriptCore/kjs/lexer.h255
-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.h490
-rw-r--r--JavaScriptCore/kjs/math_object.cpp243
-rw-r--r--JavaScriptCore/kjs/math_object.h65
-rw-r--r--JavaScriptCore/kjs/nodes.cpp5082
-rw-r--r--JavaScriptCore/kjs/nodes.h2641
-rw-r--r--JavaScriptCore/kjs/nodes2string.cpp129
-rw-r--r--JavaScriptCore/kjs/number_object.cpp522
-rw-r--r--JavaScriptCore/kjs/number_object.h76
-rw-r--r--JavaScriptCore/kjs/object.cpp693
-rw-r--r--JavaScriptCore/kjs/object.h607
-rw-r--r--JavaScriptCore/kjs/object_object.cpp216
-rw-r--r--JavaScriptCore/kjs/object_object.h57
-rw-r--r--JavaScriptCore/kjs/operations.cpp123
-rw-r--r--JavaScriptCore/kjs/operations.h114
-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.h133
-rw-r--r--JavaScriptCore/kjs/regexp.cpp166
-rw-r--r--JavaScriptCore/kjs/regexp.h81
-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.cpp1055
-rw-r--r--JavaScriptCore/kjs/string_object.h153
-rw-r--r--JavaScriptCore/kjs/testkjs.cpp344
-rw-r--r--JavaScriptCore/kjs/testkjs.pro34
-rw-r--r--JavaScriptCore/kjs/types.h25
-rw-r--r--JavaScriptCore/kjs/ustring.cpp2193
-rw-r--r--JavaScriptCore/kjs/ustring.h777
-rw-r--r--JavaScriptCore/kjs/value.cpp232
-rw-r--r--JavaScriptCore/kjs/value.h523
106 files changed, 10341 insertions, 29595 deletions
diff --git a/JavaScriptCore/kjs/Activation.h b/JavaScriptCore/kjs/Activation.h
deleted file mode 100644
index 0fdd2cc..0000000
--- a/JavaScriptCore/kjs/Activation.h
+++ /dev/null
@@ -1,99 +0,0 @@
-/*
- * 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*, int attr = None);
- 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() { 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
deleted file mode 100644
index 8c19f80..0000000
--- a/JavaScriptCore/kjs/AllInOneFile.cpp
+++ /dev/null
@@ -1,73 +0,0 @@
-// -*- 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.
- *
- */
-
-// 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
deleted file mode 100644
index 6941b58..0000000
--- a/JavaScriptCore/kjs/CollectorHeapIntrospector.cpp
+++ /dev/null
@@ -1,94 +0,0 @@
-/*
- * 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"
-
-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
deleted file mode 100644
index 76ba324..0000000
--- a/JavaScriptCore/kjs/CollectorHeapIntrospector.h
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 5f673b8..0000000
--- a/JavaScriptCore/kjs/CommonIdentifiers.cpp
+++ /dev/null
@@ -1,47 +0,0 @@
-/*
- * 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
deleted file mode 100644
index ae5c778..0000000
--- a/JavaScriptCore/kjs/CommonIdentifiers.h
+++ /dev/null
@@ -1,72 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 22816b3..0000000
--- a/JavaScriptCore/kjs/DateMath.cpp
+++ /dev/null
@@ -1,506 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 6fdad0b..0000000
--- a/JavaScriptCore/kjs/DateMath.h
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- * 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
deleted file mode 100644
index b37523e..0000000
--- a/JavaScriptCore/kjs/ExecState.cpp
+++ /dev/null
@@ -1,215 +0,0 @@
-// -*- 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
deleted file mode 100644
index b63c4ca..0000000
--- a/JavaScriptCore/kjs/ExecState.h
+++ /dev/null
@@ -1,234 +0,0 @@
-// -*- 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* e) { m_exception = e; }
- void clearException() { m_exception = 0; }
- JSValue* exception() const { return m_exception; }
- JSValue** exceptionSlot() { return &m_exception; }
- bool hadException() const { return !!m_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
deleted file mode 100644
index 4d7ea43..0000000
--- a/JavaScriptCore/kjs/JSGlobalObject.cpp
+++ /dev/null
@@ -1,621 +0,0 @@
-/*
- * 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
-
-#ifdef ANDROID_INSTRUMENT
-#define LOG_TAG "javascriptcore"
-#undef LOG
-#include <utils/Log.h>
-
-static unsigned sTotalTimeUsed;
-#endif
-
-namespace KJS {
-
-// Default number of ticks before a timeout check should be done.
-#ifdef ANDROID_MOBILE
-static const int initialTickCountThreshold = 100;
-static const int maxTickCountThreshold = 255;
-#else
-static const int initialTickCountThreshold = 255;
-#endif
-
-// 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()
-{
-#ifdef ANDROID_INSTRUMENT
-#if defined(HAVE_POSIX_CLOCKS)
- struct timespec tm;
- clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm);
- return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000;
-#endif
-#endif
-#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;
-
- d()->compatMode = NativeMode;
-
- 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, int attr)
-{
- if (symbolTablePut(propertyName, value, !(attr & ~DontDelete)))
- return;
- return JSVariableObject::put(exec, propertyName, value, attr);
-}
-
-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 | DontDelete | ReadOnly);
- d()->functionPrototype->putDirect(exec->propertyNames().constructor, d()->functionConstructor, DontEnum | DontDelete | ReadOnly);
- d()->arrayPrototype->putDirect(exec->propertyNames().constructor, d()->arrayConstructor, DontEnum | DontDelete | ReadOnly);
- d()->booleanPrototype->putDirect(exec->propertyNames().constructor, d()->booleanConstructor, DontEnum | DontDelete | ReadOnly);
- d()->stringPrototype->putDirect(exec->propertyNames().constructor, d()->stringConstructor, DontEnum | DontDelete | ReadOnly);
- d()->numberPrototype->putDirect(exec->propertyNames().constructor, d()->numberConstructor, DontEnum | DontDelete | ReadOnly);
- d()->datePrototype->putDirect(exec->propertyNames().constructor, d()->dateConstructor, DontEnum | DontDelete | ReadOnly);
- d()->regExpPrototype->putDirect(exec->propertyNames().constructor, d()->regExpConstructor, DontEnum | DontDelete | ReadOnly);
- d()->errorPrototype->putDirect(exec->propertyNames().constructor, d()->errorConstructor, DontEnum | DontDelete | ReadOnly);
- d()->evalErrorPrototype->putDirect(exec->propertyNames().constructor, d()->evalErrorConstructor, DontEnum | DontDelete | ReadOnly);
- d()->rangeErrorPrototype->putDirect(exec->propertyNames().constructor, d()->rangeErrorConstructor, DontEnum | DontDelete | ReadOnly);
- d()->referenceErrorPrototype->putDirect(exec->propertyNames().constructor, d()->referenceErrorConstructor, DontEnum | DontDelete | ReadOnly);
- d()->syntaxErrorPrototype->putDirect(exec->propertyNames().constructor, d()->syntaxErrorConstructor, DontEnum | DontDelete | ReadOnly);
- d()->typeErrorPrototype->putDirect(exec->propertyNames().constructor, d()->typeErrorConstructor, DontEnum | DontDelete | ReadOnly);
- d()->URIErrorPrototype->putDirect(exec->propertyNames().constructor, d()->URIErrorConstructor, DontEnum | DontDelete | ReadOnly);
-
- // Set global constructors
-
- // FIXME: kjs_window.cpp checks Internal/DontEnum as a performance hack, to
- // see that these values can be put directly without a check for override
- // properties.
-
- // FIXME: These properties should 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, Internal);
- putDirect("RangeError", d()->rangeErrorConstructor, Internal);
- putDirect("ReferenceError", d()->referenceErrorConstructor, Internal);
- putDirect("SyntaxError", d()->syntaxErrorConstructor, Internal);
- putDirect("TypeError", d()->typeErrorConstructor, Internal);
- putDirect("URIError", d()->URIErrorConstructor, Internal);
-
- // 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();
-#ifdef ANDROID_INSTRUMENT
- if (d()->timeoutCheckCount == 0)
- d()->startTime = getCurrentTime();
-#endif
- ++d()->timeoutCheckCount;
-}
-
-void JSGlobalObject::stopTimeoutCheck()
-{
- --d()->timeoutCheckCount;
-#ifdef ANDROID_INSTRUMENT
- if (d()->timeoutCheckCount == 0) {
- unsigned time = getCurrentTime() - d()->startTime;
- sTotalTimeUsed += time;
- if (time > 1000)
- LOGW("***** JavaScript used %d ms\n", time);
- }
-#endif
-}
-
-#ifdef ANDROID_INSTRUMENT
-void JSGlobalObject::resetTimeCounter()
-{
- sTotalTimeUsed = 0;
-}
-
-void JSGlobalObject::reportTimeCounter()
-{
- LOG(LOG_DEBUG, "WebCore", "*-* Total JavaScript (may include parsing, layout, or calcStyle) time: %d ms\n",
- sTotalTimeUsed);
-}
-#endif
-
-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;
-
-#ifdef ANDROID_MOBILE
- if (d()->ticksUntilNextTimeoutCheck > (unsigned)maxTickCountThreshold)
- d()->ticksUntilNextTimeoutCheck = maxTickCountThreshold;
-#endif
-
- if (d()->timeoutTime && d()->timeExecuting > d()->timeoutTime) {
- if (shouldInterruptScript())
-#ifdef ANDROID_INSTRUMENT
- {
- LOGW("***** JavaScript got interrupted\n");
- return true;
- }
-#else
- return true;
-#endif
-
- 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
deleted file mode 100644
index 428a17c..0000000
--- a/JavaScriptCore/kjs/JSGlobalObject.h
+++ /dev/null
@@ -1,269 +0,0 @@
-// -*- 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;
-
- enum CompatMode { NativeMode, IECompat, NetscapeCompat };
-
- 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;
- CompatMode compatMode;
-
- GlobalExecState globalExec;
- int recursion;
-
- unsigned timeoutTime;
- unsigned timeAtLastCheckTimeout;
- unsigned timeExecuting;
- unsigned timeoutCheckCount;
- unsigned tickCount;
- unsigned ticksUntilNextTimeoutCheck;
-
-#ifdef ANDROID_MOBILE
- unsigned startTime;
-#endif
- 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*, int attr = None);
-
- // 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();
-
-#ifdef ANDROID_INSTRUMENT
- static void resetTimeCounter();
- static void reportTimeCounter();
-#endif
-
- Debugger* debugger() const { return d()->debugger; }
- void setDebugger(Debugger* debugger) { d()->debugger = debugger; }
-
- // FIXME: Let's just pick one compatible behavior and go with it.
- void setCompatMode(CompatMode mode) { d()->compatMode = mode; }
- CompatMode compatMode() const { return d()->compatMode; }
-
- 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
deleted file mode 100644
index ded8ccb..0000000
--- a/JavaScriptCore/kjs/JSImmediate.cpp
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * 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
deleted file mode 100644
index bc0cb16..0000000
--- a/JavaScriptCore/kjs/JSImmediate.h
+++ /dev/null
@@ -1,278 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 9d51ca9..0000000
--- a/JavaScriptCore/kjs/JSLock.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-// -*- 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
deleted file mode 100644
index f6cda5d..0000000
--- a/JavaScriptCore/kjs/JSLock.h
+++ /dev/null
@@ -1,81 +0,0 @@
-// -*- 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
deleted file mode 100644
index 1c9418c..0000000
--- a/JavaScriptCore/kjs/JSType.h
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 76d563d..0000000
--- a/JavaScriptCore/kjs/JSVariableObject.cpp
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- * 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
deleted file mode 100644
index e82013b..0000000
--- a/JavaScriptCore/kjs/JSVariableObject.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/*
- * 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 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 checkReadOnly);
-
- 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, bool checkReadOnly)
- {
- size_t index = symbolTable().get(propertyName.ustring().rep());
- if (index == missingSymbolMarker())
- return false;
- LocalStorageEntry& entry = d->localStorage[index];
- if (checkReadOnly && (entry.attributes & ReadOnly))
- return true;
- entry.value = value;
- return true;
- }
-
-} // namespace KJS
-
-#endif // JSVariableObject_h
diff --git a/JavaScriptCore/kjs/JSWrapperObject.cpp b/JavaScriptCore/kjs/JSWrapperObject.cpp
deleted file mode 100644
index dd161f7..0000000
--- a/JavaScriptCore/kjs/JSWrapperObject.cpp
+++ /dev/null
@@ -1,34 +0,0 @@
-// -*- 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
deleted file mode 100644
index 0a06c9f..0000000
--- a/JavaScriptCore/kjs/JSWrapperObject.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// -*- 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/LabelScope.h b/JavaScriptCore/kjs/LabelScope.h
new file mode 100644
index 0000000..8c30be5
--- /dev/null
+++ b/JavaScriptCore/kjs/LabelScope.h
@@ -0,0 +1,92 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef LabelScope_h
+#define LabelScope_h
+
+#include <wtf/PassRefPtr.h>
+#include "LabelID.h"
+
+namespace JSC {
+
+ class Identifier;
+
+ class LabelScope {
+ public:
+ enum Type { Loop, Switch, NamedLabel };
+
+ LabelScope(Type type, const Identifier* name, int scopeDepth, PassRefPtr<LabelID> breakTarget, PassRefPtr<LabelID> continueTarget)
+ : m_refCount(0)
+ , m_type(type)
+ , m_name(name)
+ , m_scopeDepth(scopeDepth)
+ , m_breakTarget(breakTarget)
+ , m_continueTarget(continueTarget)
+ {
+ }
+
+ // It doesn't really make sense to copy a LabelScope, but we need this copy
+ // constructor to support moving LabelScopes in a Vector.
+
+ LabelScope(const LabelScope& other)
+ : m_refCount(other.m_refCount)
+ , m_type(other.m_type)
+ , m_name(other.m_name)
+ , m_scopeDepth(other.m_scopeDepth)
+ , m_breakTarget(other.m_breakTarget)
+ , m_continueTarget(other.m_continueTarget)
+ {
+ }
+
+ void ref() { ++m_refCount; }
+ void deref()
+ {
+ --m_refCount;
+ ASSERT(m_refCount >= 0);
+ }
+ int refCount() const { return m_refCount; }
+
+ LabelID* breakTarget() const { return m_breakTarget.get(); }
+ LabelID* continueTarget() const { return m_continueTarget.get(); }
+
+ Type type() const { return m_type; }
+ const Identifier* name() const { return m_name; }
+ int scopeDepth() const { return m_scopeDepth; }
+
+ private:
+ int m_refCount;
+ Type m_type;
+ const Identifier* m_name;
+ int m_scopeDepth;
+ RefPtr<LabelID> m_breakTarget;
+ RefPtr<LabelID> m_continueTarget;
+ };
+
+} // namespace JSC
+
+#endif // LabelScope_h
diff --git a/JavaScriptCore/kjs/LabelStack.h b/JavaScriptCore/kjs/LabelStack.h
deleted file mode 100644
index 375edf1..0000000
--- a/JavaScriptCore/kjs/LabelStack.h
+++ /dev/null
@@ -1,84 +0,0 @@
-// -*- 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
deleted file mode 100644
index 87a54bb..0000000
--- a/JavaScriptCore/kjs/LocalStorage.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// -*- 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
index 60637f2..2d11dc2 100644
--- a/JavaScriptCore/kjs/NodeInfo.h
+++ b/JavaScriptCore/kjs/NodeInfo.h
@@ -23,22 +23,41 @@
#include "nodes.h"
#include "Parser.h"
-namespace KJS {
+namespace JSC {
-template <typename T> struct NodeInfo {
- T m_node;
- ParserRefCountedData<DeclarationStacks::VarStack>* m_varDeclarations;
- ParserRefCountedData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
-};
+ template <typename T> struct NodeInfo {
+ T m_node;
+ CodeFeatures m_features;
+ int m_numConstants;
+ };
-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;
+ typedef NodeInfo<FuncDeclNode*> FuncDeclNodeInfo;
+ typedef NodeInfo<FuncExprNode*> FuncExprNodeInfo;
+ typedef NodeInfo<ExpressionNode*> ExpressionNodeInfo;
+ typedef NodeInfo<ArgumentsNode*> ArgumentsNodeInfo;
+ typedef NodeInfo<ConstDeclNode*> ConstDeclNodeInfo;
+ typedef NodeInfo<PropertyNode*> PropertyNodeInfo;
+ typedef NodeInfo<PropertyList> PropertyListInfo;
+ typedef NodeInfo<ElementList> ElementListInfo;
+ typedef NodeInfo<ArgumentList> ArgumentListInfo;
+
+ template <typename T> struct NodeDeclarationInfo {
+ T m_node;
+ ParserRefCountedData<DeclarationStacks::VarStack>* m_varDeclarations;
+ ParserRefCountedData<DeclarationStacks::FunctionStack>* m_funcDeclarations;
+ CodeFeatures m_features;
+ int m_numConstants;
+ };
+
+ typedef NodeDeclarationInfo<StatementNode*> StatementNodeInfo;
+ typedef NodeDeclarationInfo<CaseBlockNode*> CaseBlockNodeInfo;
+ typedef NodeDeclarationInfo<CaseClauseNode*> CaseClauseNodeInfo;
+ typedef NodeDeclarationInfo<SourceElements*> SourceElementsInfo;
+ typedef NodeDeclarationInfo<ClauseList> ClauseListInfo;
+ typedef NodeDeclarationInfo<ExpressionNode*> VarDeclListInfo;
+ typedef NodeDeclarationInfo<ConstDeclList> ConstDeclListInfo;
+ typedef NodeDeclarationInfo<ParameterList> ParameterListInfo;
-} // namespace KJS
+} // namespace JSC
#endif // NodeInfo_h
diff --git a/JavaScriptCore/kjs/Parser.cpp b/JavaScriptCore/kjs/Parser.cpp
index c6d7265..26773e8 100644
--- a/JavaScriptCore/kjs/Parser.cpp
+++ b/JavaScriptCore/kjs/Parser.cpp
@@ -1,9 +1,7 @@
-// -*- 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.
+ * Copyright (C) 2003, 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
@@ -25,67 +23,55 @@
#include "config.h"
#include "Parser.h"
+#include "Debugger.h"
#include "lexer.h"
#include <wtf/HashSet.h>
#include <wtf/Vector.h>
-extern int kjsyyparse();
+extern int kjsyyparse(void*);
-namespace KJS {
+namespace JSC {
-Parser::Parser()
- : m_sourceId(0)
-{
-}
-
-void Parser::parse(int startingLineNumber,
- const UChar* code, unsigned length,
- int* sourceId, int* errLine, UString* errMsg)
+void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg)
{
ASSERT(!m_sourceElements);
- if (errLine)
- *errLine = -1;
- if (errMsg)
- *errMsg = 0;
-
- Lexer& lexer = KJS::lexer();
+ int defaultErrLine;
+ UString defaultErrMsg;
+
+ if (!errLine)
+ errLine = &defaultErrLine;
+ if (!errMsg)
+ errMsg = &defaultErrMsg;
+
+ *errLine = -1;
+ *errMsg = 0;
- lexer.setCode(startingLineNumber, code, length);
- m_sourceId++;
- if (sourceId)
- *sourceId = m_sourceId;
+ Lexer& lexer = *globalData->lexer;
+ lexer.setCode(*m_source);
- int parseError = kjsyyparse();
+ int parseError = kjsyyparse(globalData);
bool lexError = lexer.sawError();
lexer.clear();
- ParserRefCounted::deleteNewObjects();
+ ParserRefCounted::deleteNewObjects(globalData);
if (parseError || lexError) {
- if (errLine)
- *errLine = lexer.lineNo();
- if (errMsg)
- *errMsg = "Parse error";
+ *errLine = lexer.lineNo();
+ *errMsg = "Parse error";
m_sourceElements.clear();
}
}
void Parser::didFinishParsing(SourceElements* sourceElements, ParserRefCountedData<DeclarationStacks::VarStack>* varStack,
- ParserRefCountedData<DeclarationStacks::FunctionStack>* funcStack, int lastLine)
+ ParserRefCountedData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants)
{
- m_sourceElements = sourceElements ? sourceElements : new SourceElements;
+ m_sourceElements = sourceElements;
m_varDeclarations = varStack;
m_funcDeclarations = funcStack;
+ m_features = features;
m_lastLine = lastLine;
+ m_numConstants = numConstants;
}
-Parser& parser()
-{
- ASSERT(JSLock::currentThreadIsHoldingLock());
-
- static Parser& staticParser = *new Parser;
- return staticParser;
-}
-
-} // namespace KJS
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/Parser.h b/JavaScriptCore/kjs/Parser.h
index 92548fe..c2f55d7 100644
--- a/JavaScriptCore/kjs/Parser.h
+++ b/JavaScriptCore/kjs/Parser.h
@@ -1,9 +1,7 @@
-// -*- 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.
+ * Copyright (C) 2003, 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
@@ -25,75 +23,75 @@
#ifndef Parser_h
#define Parser_h
+#include "SourceProvider.h"
+#include "Debugger.h"
+#include "nodes.h"
#include <wtf/Forward.h>
#include <wtf/Noncopyable.h>
#include <wtf/OwnPtr.h>
#include <wtf/RefPtr.h>
-#include "nodes.h"
-namespace KJS {
+namespace JSC {
class FunctionBodyNode;
class ProgramNode;
class UString;
- struct UChar;
+ template <typename T>
+ struct ParserRefCountedData : ParserRefCounted {
+ ParserRefCountedData(JSGlobalData* globalData)
+ : ParserRefCounted(globalData)
+ {
+ }
- 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; }
+ template <class ParsedNode> PassRefPtr<ParsedNode> parse(ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0);
void didFinishParsing(SourceElements*, ParserRefCountedData<DeclarationStacks::VarStack>*,
- ParserRefCountedData<DeclarationStacks::FunctionStack>*, int lastLine);
+ ParserRefCountedData<DeclarationStacks::FunctionStack>*, CodeFeatures features, int lastLine, int numConstants);
private:
- friend Parser& parser();
+ void parse(JSGlobalData*, int* errLine, UString* errMsg);
- 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;
+ const SourceCode* m_source;
RefPtr<SourceElements> m_sourceElements;
RefPtr<ParserRefCountedData<DeclarationStacks::VarStack> > m_varDeclarations;
RefPtr<ParserRefCountedData<DeclarationStacks::FunctionStack> > m_funcDeclarations;
+ CodeFeatures m_features;
int m_lastLine;
+ int m_numConstants;
};
-
- 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)
+ template <class ParsedNode> PassRefPtr<ParsedNode> Parser::parse(ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg)
{
- m_sourceURL = sourceURL;
- parse(startingLineNumber, code, length, sourceId, errLine, errMsg);
- if (!m_sourceElements) {
- m_sourceURL = UString();
- return 0;
+ m_source = &source;
+ parse(&exec->globalData(), errLine, errMsg);
+ RefPtr<ParsedNode> result;
+ if (m_sourceElements) {
+ result = ParsedNode::create(&exec->globalData(),
+ m_sourceElements.get(),
+ m_varDeclarations ? &m_varDeclarations->data : 0,
+ m_funcDeclarations ? &m_funcDeclarations->data : 0,
+ *m_source,
+ m_features,
+ m_numConstants);
+ result->setLoc(m_source->firstLine(), m_lastLine);
}
- RefPtr<ParsedNode> node = ParsedNode::create(m_sourceElements.release().get(),
- m_varDeclarations ? &m_varDeclarations->data : 0,
- m_funcDeclarations ? &m_funcDeclarations->data : 0);
+
+ m_source = 0;
+ m_sourceElements = 0;
m_varDeclarations = 0;
m_funcDeclarations = 0;
- m_sourceURL = UString();
- node->setLoc(startingLineNumber, m_lastLine);
- return node.release();
+
+ if (debugger)
+ debugger->sourceParsed(exec, source, *errLine, *errMsg);
+ return result.release();
}
-} // namespace KJS
+} // namespace JSC
#endif // Parser_h
diff --git a/JavaScriptCore/kjs/PropertyNameArray.cpp b/JavaScriptCore/kjs/PropertyNameArray.cpp
deleted file mode 100644
index 45dda3a..0000000
--- a/JavaScriptCore/kjs/PropertyNameArray.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-// -*- 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
deleted file mode 100644
index b702d21..0000000
--- a/JavaScriptCore/kjs/PropertyNameArray.h
+++ /dev/null
@@ -1,56 +0,0 @@
-// -*- 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/ResultType.h b/JavaScriptCore/kjs/ResultType.h
new file mode 100644
index 0000000..f838ce0
--- /dev/null
+++ b/JavaScriptCore/kjs/ResultType.h
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef ResultType_h
+#define ResultType_h
+
+namespace JSC {
+
+ struct ResultType {
+ friend struct OperandTypes;
+
+ typedef char Type;
+ static const Type TypeReusable = 1;
+
+ static const Type TypeMaybeNumber = 2;
+ static const Type TypeMaybeString = 4;
+ static const Type TypeMaybeNull = 8;
+ static const Type TypeMaybeBool = 16;
+ static const Type TypeMaybeOther = 32;
+
+ static const Type TypeReusableNumber = 3;
+ static const Type TypeStringOrReusableNumber = 4;
+
+ explicit ResultType(Type type)
+ : m_type(type)
+ {
+ }
+
+ bool isReusable()
+ {
+ return (m_type & TypeReusable);
+ }
+
+ bool isReusableNumber()
+ {
+ return isReusable() && definitelyIsNumber();
+ }
+
+ bool definitelyIsNumber()
+ {
+ return ((m_type & ~TypeReusable) == TypeMaybeNumber);
+ }
+
+ bool isNotNumber()
+ {
+ return ((m_type & TypeMaybeNumber) == 0);
+ }
+
+ bool mightBeNumber()
+ {
+ return !isNotNumber();
+ }
+
+ int toInt()
+ {
+ return static_cast<int>(m_type);
+ }
+
+ static ResultType nullType()
+ {
+ return ResultType(TypeMaybeNull);
+ }
+
+ static ResultType boolean()
+ {
+ return ResultType(TypeMaybeBool);
+ }
+
+ static ResultType constNumber()
+ {
+ return ResultType(TypeMaybeNumber);
+ }
+
+ static ResultType reusableNumber()
+ {
+ return ResultType(TypeReusable | TypeMaybeNumber);
+ }
+
+ static ResultType reusableNumberOrString()
+ {
+ return ResultType(TypeReusable | TypeMaybeNumber | TypeMaybeString);
+ }
+
+ static ResultType string()
+ {
+ return ResultType(TypeMaybeString);
+ }
+
+ static ResultType unknown()
+ {
+ return ResultType(TypeMaybeNumber | TypeMaybeString | TypeMaybeNull | TypeMaybeBool | TypeMaybeOther);
+ }
+
+ static ResultType forAdd(ResultType op1, ResultType op2)
+ {
+ if (op1.definitelyIsNumber() && op2.definitelyIsNumber())
+ return reusableNumber();
+ if (op1.isNotNumber() || op2.isNotNumber())
+ return string();
+ return reusableNumberOrString();
+ }
+
+ private:
+ Type m_type;
+ };
+
+ struct OperandTypes
+ {
+ OperandTypes(ResultType first = ResultType::unknown(), ResultType second = ResultType::unknown())
+ {
+ m_u.rds.first = first.m_type;
+ m_u.rds.second = second.m_type;
+ }
+
+ union {
+ struct {
+ ResultType::Type first;
+ ResultType::Type second;
+ } rds;
+ int i;
+ } m_u;
+
+ ResultType first()
+ {
+ return ResultType(m_u.rds.first);
+ }
+
+ ResultType second()
+ {
+ return ResultType(m_u.rds.second);
+ }
+
+ int toInt()
+ {
+ return m_u.i;
+ }
+ static OperandTypes fromInt(int value)
+ {
+ OperandTypes types;
+ types.m_u.i = value;
+ return types;
+ }
+ };
+
+} // namespace JSC
+
+#endif // ResultType_h
diff --git a/JavaScriptCore/kjs/SavedBuiltins.h b/JavaScriptCore/kjs/SavedBuiltins.h
deleted file mode 100644
index 9901e41..0000000
--- a/JavaScriptCore/kjs/SavedBuiltins.h
+++ /dev/null
@@ -1,94 +0,0 @@
-// -*- 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/Shell.cpp b/JavaScriptCore/kjs/Shell.cpp
new file mode 100644
index 0000000..f35679e
--- /dev/null
+++ b/JavaScriptCore/kjs/Shell.cpp
@@ -0,0 +1,501 @@
+/*
+ * 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 "CodeGenerator.h"
+#include "InitializeThreading.h"
+#include "JSArray.h"
+#include "JSLock.h"
+#include "PrototypeFunction.h"
+#include "SamplingTool.h"
+#include "completion.h"
+#include "interpreter.h"
+#include <math.h>
+#include <stdio.h>
+#include <string.h>
+
+#if !PLATFORM(WIN_OS)
+#include <unistd.h>
+#endif
+
+#if HAVE(READLINE)
+#include <readline/history.h>
+#include <readline/readline.h>
+#endif
+
+#if HAVE(SYS_TIME_H)
+#include <sys/time.h>
+#endif
+
+#if PLATFORM(UNIX)
+#include <signal.h>
+#endif
+
+#if COMPILER(MSVC)
+#include <crtdbg.h>
+#include <windows.h>
+#endif
+
+#if PLATFORM(QT)
+#include <QCoreApplication>
+#include <QDateTime>
+#endif
+
+using namespace JSC;
+using namespace WTF;
+
+static bool fillBufferWithContentsOfFile(const UString& fileName, Vector<char>& buffer);
+
+static JSValue* functionPrint(ExecState*, JSObject*, JSValue*, const ArgList&);
+static JSValue* functionDebug(ExecState*, JSObject*, JSValue*, const ArgList&);
+static JSValue* functionGC(ExecState*, JSObject*, JSValue*, const ArgList&);
+static JSValue* functionVersion(ExecState*, JSObject*, JSValue*, const ArgList&);
+static JSValue* functionRun(ExecState*, JSObject*, JSValue*, const ArgList&);
+static JSValue* functionLoad(ExecState*, JSObject*, JSValue*, const ArgList&);
+static JSValue* functionReadline(ExecState*, JSObject*, JSValue*, const ArgList&);
+static JSValue* functionQuit(ExecState*, JSObject*, JSValue*, const ArgList&);
+
+struct Options {
+ Options()
+ : interactive(false)
+ , prettyPrint(false)
+ , dump(false)
+ {
+ }
+
+ bool interactive;
+ bool prettyPrint;
+ bool dump;
+ Vector<UString> fileNames;
+ Vector<UString> arguments;
+};
+
+static const char interactivePrompt[] = "> ";
+static const UString interpreterName("Interpreter");
+
+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(const Vector<UString>& arguments);
+ virtual UString className() const { return "global"; }
+};
+COMPILE_ASSERT(!IsInteger<GlobalObject>::value, WTF_IsInteger_GlobalObject_false);
+ASSERT_CLASS_FITS_IN_CELL(GlobalObject);
+
+GlobalObject::GlobalObject(const Vector<UString>& arguments)
+ : JSGlobalObject()
+{
+ putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "debug"), functionDebug));
+ putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "print"), functionPrint));
+ putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "quit"), functionQuit));
+ putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "gc"), functionGC));
+ putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "version"), functionVersion));
+ putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "run"), functionRun));
+ putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 1, Identifier(globalExec(), "load"), functionLoad));
+ putDirectFunction(globalExec(), new (globalExec()) PrototypeFunction(globalExec(), prototypeFunctionStructure(), 0, Identifier(globalExec(), "readline"), functionReadline));
+
+ JSObject* array = constructEmptyArray(globalExec());
+ for (size_t i = 0; i < arguments.size(); ++i)
+ array->put(globalExec(), i, jsString(globalExec(), arguments[i]));
+ putDirect(Identifier(globalExec(), "arguments"), array);
+}
+
+JSValue* functionPrint(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
+{
+ for (unsigned i = 0; i < args.size(); ++i) {
+ if (i != 0)
+ putchar(' ');
+
+ printf("%s", args.at(exec, i)->toString(exec).UTF8String().c_str());
+ }
+
+ putchar('\n');
+ fflush(stdout);
+ return jsUndefined();
+}
+
+JSValue* functionDebug(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
+{
+ fprintf(stderr, "--> %s\n", args.at(exec, 0)->toString(exec).UTF8String().c_str());
+ return jsUndefined();
+}
+
+JSValue* functionGC(ExecState* exec, JSObject*, JSValue*, const ArgList&)
+{
+ JSLock lock(false);
+ exec->heap()->collect();
+ return jsUndefined();
+}
+
+JSValue* functionVersion(ExecState*, JSObject*, JSValue*, const ArgList&)
+{
+ // 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*, JSValue*, const ArgList& args)
+{
+ StopWatch stopWatch;
+ UString fileName = args.at(exec, 0)->toString(exec);
+ Vector<char> script;
+ if (!fillBufferWithContentsOfFile(fileName, script))
+ return throwError(exec, GeneralError, "Could not open file.");
+
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+
+ stopWatch.start();
+ Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
+ stopWatch.stop();
+
+ return jsNumber(globalObject->globalExec(), stopWatch.getElapsedMS());
+}
+
+JSValue* functionLoad(ExecState* exec, JSObject*, JSValue*, const ArgList& args)
+{
+ UString fileName = args.at(exec, 0)->toString(exec);
+ Vector<char> script;
+ if (!fillBufferWithContentsOfFile(fileName, script))
+ return throwError(exec, GeneralError, "Could not open file.");
+
+ JSGlobalObject* globalObject = exec->lexicalGlobalObject();
+ Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
+
+ return jsUndefined();
+}
+
+JSValue* functionReadline(ExecState* exec, JSObject*, JSValue*, const ArgList&)
+{
+ 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(exec, line.data());
+}
+
+JSValue* functionQuit(ExecState*, JSObject*, JSValue*, const ArgList&)
+{
+ 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 jscmain function requires object
+// unwinding.
+
+#if COMPILER(MSVC) && !defined(_DEBUG)
+#define TRY __try {
+#define EXCEPT(x) } __except (EXCEPTION_EXECUTE_HANDLER) { x; }
+#else
+#define TRY
+#define EXCEPT(x)
+#endif
+
+int jscmain(int argc, char** argv, JSGlobalData*);
+
+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
+
+#if PLATFORM(QT)
+ QCoreApplication app(argc, argv);
+#endif
+
+ int res = 0;
+ TRY
+ res = jscmain(argc, argv, JSGlobalData::create().releaseRef());
+ EXCEPT(res = 3)
+ return res;
+}
+
+static bool prettyPrintScript(ExecState* exec, const UString& fileName, const Vector<char>& script)
+{
+ int errLine = 0;
+ UString errMsg;
+ RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), makeSource(script.data(), fileName), &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(GlobalObject* globalObject, const Vector<UString>& fileNames, bool prettyPrint, bool dump)
+{
+ Vector<char> script;
+
+ if (dump)
+ CodeGenerator::setDumpsGeneratedCode(true);
+
+#if ENABLE(OPCODE_SAMPLING)
+ Machine* machine = globalObject->globalData()->machine;
+ machine->setSampler(new SamplingTool(machine));
+#endif
+
+ 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(globalObject->globalExec(), fileName, script);
+ else {
+#if ENABLE(OPCODE_SAMPLING)
+ machine->sampler()->start();
+#endif
+ Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script.data(), fileName));
+ success = success && completion.complType() != Throw;
+ if (dump) {
+ if (completion.complType() == Throw)
+ printf("Exception: %s\n", completion.value()->toString(globalObject->globalExec()).ascii());
+ else
+ printf("End: %s\n", completion.value()->toString(globalObject->globalExec()).ascii());
+ }
+
+ globalObject->globalExec()->clearException();
+
+#if ENABLE(OPCODE_SAMPLING)
+ machine->sampler()->stop();
+#endif
+ }
+ }
+
+#if ENABLE(OPCODE_SAMPLING)
+ machine->sampler()->dump(globalObject->globalExec());
+ delete machine->sampler();
+#endif
+ return success;
+}
+
+static void runInteractive(GlobalObject* globalObject)
+{
+ while (true) {
+#if HAVE(READLINE)
+ char* line = readline(interactivePrompt);
+ if (!line)
+ break;
+ if (line[0])
+ add_history(line);
+ Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line, interpreterName));
+ free(line);
+#else
+ puts(interactivePrompt);
+ 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');
+ Completion completion = Interpreter::evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(line.data(), interpreterName));
+#endif
+ if (completion.complType() == Throw)
+ printf("Exception: %s\n", completion.value()->toString(globalObject->globalExec()).ascii());
+ else
+ printf("%s\n", completion.value()->toString(globalObject->globalExec()).UTF8String().c_str());
+
+ globalObject->globalExec()->clearException();
+ }
+ printf("\n");
+}
+
+static void printUsageStatement()
+{
+ fprintf(stderr, "Usage: jsc [options] [files] [-- arguments]\n");
+ fprintf(stderr, " -d Dumps bytecode (debug builds only)\n");
+ fprintf(stderr, " -f Specifies a source file (deprecated)\n");
+ fprintf(stderr, " -h|--help Prints this help message\n");
+ fprintf(stderr, " -i Enables interactive mode (default if no files are specified)\n");
+ fprintf(stderr, " -p Prints formatted source code\n");
+ fprintf(stderr, " -s Installs signal handlers that exit on a crash (Unix platforms only)\n");
+ exit(-1);
+}
+
+static void parseArguments(int argc, char** argv, Options& options)
+{
+ int i = 1;
+ for (; i < argc; ++i) {
+ const char* arg = argv[i];
+ if (strcmp(arg, "-f") == 0) {
+ if (++i == argc)
+ printUsageStatement();
+ options.fileNames.append(argv[i]);
+ continue;
+ }
+ if (strcmp(arg, "-h") == 0 || strcmp(arg, "--help") == 0) {
+ printUsageStatement();
+ }
+ if (strcmp(arg, "-i") == 0) {
+ options.interactive = true;
+ continue;
+ }
+ if (strcmp(arg, "-p") == 0) {
+ options.prettyPrint = true;
+ continue;
+ }
+ if (strcmp(arg, "-d") == 0) {
+ options.dump = true;
+ continue;
+ }
+ if (strcmp(arg, "-s") == 0) {
+#if PLATFORM(UNIX)
+ signal(SIGILL, _exit);
+ signal(SIGFPE, _exit);
+ signal(SIGBUS, _exit);
+ signal(SIGSEGV, _exit);
+#endif
+ continue;
+ }
+ if (strcmp(arg, "--") == 0) {
+ ++i;
+ break;
+ }
+ options.fileNames.append(argv[i]);
+ }
+
+ if (options.fileNames.isEmpty())
+ options.interactive = true;
+
+ for (; i < argc; ++i)
+ options.arguments.append(argv[i]);
+}
+
+int jscmain(int argc, char** argv, JSGlobalData* globalData)
+{
+ JSC::initializeThreading();
+
+ JSLock lock(false);
+
+ Options options;
+ parseArguments(argc, argv, options);
+
+ GlobalObject* globalObject = new (globalData) GlobalObject(options.arguments);
+ bool success = runWithScripts(globalObject, options.fileNames, options.prettyPrint, options.dump);
+ if (options.interactive && success)
+ runInteractive(globalObject);
+
+ 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/SourceCode.h b/JavaScriptCore/kjs/SourceCode.h
new file mode 100644
index 0000000..2840161
--- /dev/null
+++ b/JavaScriptCore/kjs/SourceCode.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Apple Computer, Inc. ("Apple") nor the names of
+ * its contributors may be used to endorse or promote products derived
+ * from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef SourceCode_h
+#define SourceCode_h
+
+#include "SourceProvider.h"
+#include <wtf/RefPtr.h>
+
+namespace JSC {
+
+ class SourceCode {
+ public:
+ SourceCode()
+ : m_startChar(0)
+ , m_endChar(0)
+ , m_firstLine(0)
+ {
+ }
+
+ SourceCode(PassRefPtr<SourceProvider> provider, int firstLine = 1)
+ : m_provider(provider)
+ , m_startChar(0)
+ , m_endChar(m_provider->length())
+ , m_firstLine(std::max(firstLine, 1))
+ {
+ }
+
+ SourceCode(PassRefPtr<SourceProvider> provider, int start, int end, int firstLine)
+ : m_provider(provider)
+ , m_startChar(start)
+ , m_endChar(end)
+ , m_firstLine(std::max(firstLine, 1))
+ {
+ }
+
+ UString toString() const
+ {
+ if (!m_provider)
+ return UString();
+ return m_provider->getRange(m_startChar, m_endChar);
+ }
+
+ bool isNull() const { return !m_provider; }
+ SourceProvider* provider() const { return m_provider.get(); }
+ int firstLine() const { return m_firstLine; }
+ int startOffset() const { return m_startChar; }
+ const UChar* data() const { return m_provider->data() + m_startChar; }
+ int length() const { return m_endChar - m_startChar; }
+
+ private:
+ RefPtr<SourceProvider> m_provider;
+ int m_startChar;
+ int m_endChar;
+ int m_firstLine;
+ };
+
+ inline SourceCode makeSource(const UString& source, const UString& url = UString(), int firstLine = 1)
+ {
+ return SourceCode(UStringSourceProvider::create(source, url), firstLine);
+ }
+
+} // namespace JSC
+
+#endif // SourceCode_h
diff --git a/JavaScriptCore/kjs/SymbolTable.h b/JavaScriptCore/kjs/SourceProvider.h
index 1c2b2e8..755a10f 100644
--- a/JavaScriptCore/kjs/SymbolTable.h
+++ b/JavaScriptCore/kjs/SourceProvider.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -26,43 +26,54 @@
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-#ifndef SymbolTable_h
-#define SymbolTable_h
+#ifndef SourceProvider_h
+#define SourceProvider_h
#include "ustring.h"
-#include <wtf/AlwaysInline.h>
+#include <wtf/RefCounted.h>
-namespace KJS {
+namespace JSC {
- 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()
+ class SourceProvider : public RefCounted<SourceProvider> {
+ public:
+ SourceProvider(const UString& url)
+ : m_url(url)
{
- return *reinterpret_cast<RefPtr<UString::Rep>*>(&nullRepPtr);
}
+ virtual ~SourceProvider() { }
+
+ virtual UString getRange(int start, int end) const = 0;
+ virtual const UChar* data() const = 0;
+ virtual int length() const = 0;
+
+ const UString& url() { return m_url; }
+ intptr_t asID() { return reinterpret_cast<intptr_t>(this); }
private:
- static UString::Rep* nullRepPtr;
+ UString m_url;
};
- static ALWAYS_INLINE size_t missingSymbolMarker() { return std::numeric_limits<size_t>::max(); }
+ class UStringSourceProvider : public SourceProvider {
+ public:
+ static PassRefPtr<UStringSourceProvider> create(const UString& source, const UString& url)
+ {
+ return adoptRef(new UStringSourceProvider(source, url));
+ }
- 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;
- };
+ UString getRange(int start, int end) const { return m_source.substr(start, end - start); }
+ const UChar* data() const { return m_source.data(); }
+ int length() const { return m_source.size(); }
- typedef HashMap<RefPtr<UString::Rep>, size_t, IdentifierRepHash, IdentifierRepHashTraits, SymbolTableIndexHashTraits> SymbolTable;
+ private:
+ UStringSourceProvider(const UString& source, const UString& url)
+ : SourceProvider(url)
+ , m_source(source)
+ {
+ }
-} // namespace KJS
+ UString m_source;
+ };
+
+} // namespace JSC
-#endif // SymbolTable_h
+#endif // SourceProvider_h
diff --git a/JavaScriptCore/kjs/TypeInfo.h b/JavaScriptCore/kjs/TypeInfo.h
new file mode 100644
index 0000000..4f0b16c
--- /dev/null
+++ b/JavaScriptCore/kjs/TypeInfo.h
@@ -0,0 +1,63 @@
+// -*- mode: c++; c-basic-offset: 4 -*-
+/*
+ * Copyright (C) 2008 Apple Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef TypeInfo_h
+#define TypeInfo_h
+
+#include "JSType.h"
+
+namespace JSC {
+
+ // WebCore uses MasqueradesAsUndefined to make document.all and style.filter undetectable.
+ static const unsigned MasqueradesAsUndefined = 1;
+ static const unsigned ImplementsHasInstance = 1 << 1;
+ static const unsigned OverridesHasInstance = 1 << 2;
+ static const unsigned NeedsThisConversion = 1 << 3;
+ static const unsigned HasStandardGetOwnPropertySlot = 1 << 4;
+
+ class TypeInfo {
+ friend class CTI;
+ public:
+ TypeInfo(JSType type, unsigned flags = 0) : m_type(type), m_flags(flags) { }
+
+ JSType type() const { return m_type; }
+
+ bool masqueradesAsUndefined() const { return m_flags & MasqueradesAsUndefined; }
+ bool implementsHasInstance() const { return m_flags & ImplementsHasInstance; }
+ bool overridesHasInstance() const { return m_flags & OverridesHasInstance; }
+ bool needsThisConversion() const { return m_flags & NeedsThisConversion; }
+ bool hasStandardGetOwnPropertySlot() const { return m_flags & HasStandardGetOwnPropertySlot; }
+
+ unsigned flags() const { return m_flags; }
+
+ private:
+ JSType m_type;
+ unsigned m_flags;
+ };
+
+}
+
+#endif // TypeInfo_h
diff --git a/JavaScriptCore/kjs/array_instance.cpp b/JavaScriptCore/kjs/array_instance.cpp
deleted file mode 100644
index 0578ed7..0000000
--- a/JavaScriptCore/kjs/array_instance.cpp
+++ /dev/null
@@ -1,605 +0,0 @@
-/*
- * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2007 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, int attributes)
-{
- bool isArrayIndex;
- unsigned i = propertyName.toArrayIndex(&isArrayIndex);
- if (isArrayIndex) {
- put(exec, i, value, attributes);
- 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, attributes);
-}
-
-void ArrayInstance::put(ExecState* exec, unsigned i, JSValue* value, int attributes)
-{
- if (i > maxArrayIndex) {
- put(exec, Identifier::from(i), value, attributes);
- 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
deleted file mode 100644
index 913d0cd..0000000
--- a/JavaScriptCore/kjs/array_instance.h
+++ /dev/null
@@ -1,72 +0,0 @@
-// -*- 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*, int attributes = None);
- virtual void put(ExecState*, unsigned propertyName, JSValue*, int attributes = None);
- 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
deleted file mode 100644
index 48b0855..0000000
--- a/JavaScriptCore/kjs/array_object.cpp
+++ /dev/null
@@ -1,760 +0,0 @@
-/*
- * 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
deleted file mode 100644
index e109c47..0000000
--- a/JavaScriptCore/kjs/array_object.h
+++ /dev/null
@@ -1,71 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 10bb738..0000000
--- a/JavaScriptCore/kjs/bool_object.cpp
+++ /dev/null
@@ -1,117 +0,0 @@
-/*
- * 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
deleted file mode 100644
index c3d5a9f..0000000
--- a/JavaScriptCore/kjs/bool_object.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * 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
index f0369c6..53e889e 100644
--- a/JavaScriptCore/kjs/collector.cpp
+++ b/JavaScriptCore/kjs/collector.cpp
@@ -1,6 +1,5 @@
-// -*- mode: c++; c-basic-offset: 4 -*-
/*
- * Copyright (C) 2003, 2004, 2005, 2006, 2007 Apple Inc. All rights reserved.
+ * 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
@@ -22,11 +21,15 @@
#include "config.h"
#include "collector.h"
+#include "ArgList.h"
+#include "CollectorHeapIterator.h"
#include "ExecState.h"
#include "JSGlobalObject.h"
-#include "internal.h"
-#include "list.h"
-#include "value.h"
+#include "JSLock.h"
+#include "JSString.h"
+#include "JSValue.h"
+#include "Machine.h"
+#include "Tracing.h"
#include <algorithm>
#include <setjmp.h>
#include <stdlib.h>
@@ -34,10 +37,6 @@
#include <wtf/HashCountedSet.h>
#include <wtf/UnusedParam.h>
-#if USE(MULTIPLE_THREADS)
-#include <pthread.h>
-#endif
-
#if PLATFORM(DARWIN)
#include <mach/mach_port.h>
@@ -46,8 +45,6 @@
#include <mach/thread_act.h>
#include <mach/vm_map.h>
-#include "CollectorHeapIntrospector.h"
-
#elif PLATFORM(WIN_OS)
#include <windows.h>
@@ -62,54 +59,139 @@
#include <thread.h>
#endif
+#if PLATFORM(LINUX)
+#include <pthread.h>
+#endif
+
+#if PLATFORM(OPENBSD)
+#include <pthread.h>
+#endif
+
#if HAVE(PTHREAD_NP_H)
#include <pthread_np.h>
-#else
-#include <pthread.h>
#endif
#endif
#define DEBUG_COLLECTOR 0
+#define COLLECT_ON_EVERY_ALLOCATION 0
using std::max;
-namespace KJS {
+namespace JSC {
// 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;
+// This value has to be a macro to be used in max() without introducing
+// a PIC branch in Mach-O binaries, see <rdar://problem/5971391>.
+#define MIN_ARRAY_SIZE (static_cast<size_t>(14))
-enum OperationInProgress { NoOperation, Allocation, Collection };
+static void freeHeap(CollectorHeap*);
-struct CollectorHeap {
- CollectorBlock** blocks;
- size_t numBlocks;
- size_t usedBlocks;
- size_t firstBlockWithPossibleSpace;
-
- size_t numLiveObjects;
- size_t numLiveObjectsAtLastCollect;
- size_t extraCost;
+#if ENABLE(JSC_MULTIPLE_THREADS)
- OperationInProgress operationInProgress;
+#if PLATFORM(DARWIN)
+typedef mach_port_t PlatformThread;
+#elif PLATFORM(WIN_OS)
+struct PlatformThread {
+ PlatformThread(DWORD _id, HANDLE _handle) : id(_id), handle(_handle) {}
+ DWORD id;
+ HANDLE handle;
};
+#endif
+
+class Heap::Thread {
+public:
+ Thread(pthread_t pthread, const PlatformThread& platThread, void* base)
+ : posixThread(pthread)
+ , platformThread(platThread)
+ , stackBase(base)
+ {
+ }
-static CollectorHeap primaryHeap = { 0, 0, 0, 0, 0, 0, 0, NoOperation };
-static CollectorHeap numberHeap = { 0, 0, 0, 0, 0, 0, 0, NoOperation };
+ Thread* next;
+ pthread_t posixThread;
+ PlatformThread platformThread;
+ void* stackBase;
+};
-// 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;
+#endif
-static CollectorBlock* allocateBlock()
+Heap::Heap(JSGlobalData* globalData)
+ : m_markListSet(0)
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ , m_registeredThreads(0)
+#endif
+ , m_globalData(globalData)
{
-#if PLATFORM(DARWIN)
+ ASSERT(globalData);
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ int error = pthread_key_create(&m_currentThreadRegistrar, unregisterThread);
+ if (error)
+ CRASH();
+#endif
+
+ memset(&primaryHeap, 0, sizeof(CollectorHeap));
+ memset(&numberHeap, 0, sizeof(CollectorHeap));
+}
+
+Heap::~Heap()
+{
+ // The destroy function must already have been called, so assert this.
+ ASSERT(!m_globalData);
+}
+
+void Heap::destroy()
+{
+ JSLock lock(false);
+
+ if (!m_globalData)
+ return;
+
+ // The global object is not GC protected at this point, so sweeping may delete it
+ // (and thus the global data) before other objects that may use the global data.
+ RefPtr<JSGlobalData> protect(m_globalData);
+
+ delete m_markListSet;
+ m_markListSet = 0;
+
+ sweep<PrimaryHeap>();
+ // No need to sweep number heap, because the JSNumber destructor doesn't do anything.
+
+ ASSERT(!primaryHeap.numLiveObjects);
+
+ freeHeap(&primaryHeap);
+ freeHeap(&numberHeap);
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+#ifndef NDEBUG
+ int error =
+#endif
+ pthread_key_delete(m_currentThreadRegistrar);
+ ASSERT(!error);
+
+ MutexLocker registeredThreadsLock(m_registeredThreadsMutex);
+ for (Heap::Thread* t = m_registeredThreads; t;) {
+ Heap::Thread* next = t->next;
+ delete t;
+ t = next;
+ }
+#endif
+
+ m_globalData = 0;
+}
+
+template <HeapType heapType>
+static NEVER_INLINE CollectorBlock* allocateBlock()
+{
+#if PLATFORM(DARWIN)
vm_address_t address = 0;
+ // FIXME: tag the region as a JavaScriptCore heap when we get a registered VM tag: <rdar://problem/6054788>.
vm_map(current_task(), &address, BLOCK_SIZE, BLOCK_OFFSET_MASK, VM_FLAGS_ANYWHERE, 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
@@ -119,8 +201,12 @@ static CollectorBlock* allocateBlock()
posix_memalign(&address, BLOCK_SIZE, BLOCK_SIZE);
memset(address, 0, BLOCK_SIZE);
#else
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+#error Need to initialize pagesize safely.
+#endif
static size_t pagesize = getpagesize();
-
+
size_t extra = 0;
if (BLOCK_SIZE > pagesize)
extra = BLOCK_SIZE - pagesize;
@@ -133,15 +219,15 @@ static CollectorBlock* allocateBlock()
adjust = BLOCK_SIZE - (address & BLOCK_OFFSET_MASK);
if (adjust > 0)
- munmap(reinterpret_cast<void*>(address), adjust);
+ munmap(reinterpret_cast<char*>(address), adjust);
if (adjust < extra)
- munmap(reinterpret_cast<void*>(address + adjust + BLOCK_SIZE), extra - adjust);
+ munmap(reinterpret_cast<char*>(address + adjust + BLOCK_SIZE), extra - adjust);
address += adjust;
memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE);
#endif
-
+ reinterpret_cast<CollectorBlock*>(address)->type = heapType;
return reinterpret_cast<CollectorBlock*>(address);
}
@@ -150,15 +236,24 @@ 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);
+ VirtualFree(block, 0, MEM_RELEASE);
#elif HAVE(POSIX_MEMALIGN)
free(block);
#else
- munmap(block, BLOCK_SIZE);
+ munmap(reinterpret_cast<char*>(block), BLOCK_SIZE);
#endif
}
-void Collector::recordExtraCost(size_t cost)
+static void freeHeap(CollectorHeap* heap)
+{
+ for (size_t i = 0; i < heap->usedBlocks; ++i)
+ if (heap->blocks[i])
+ freeBlock(heap->blocks[i]);
+ fastFree(heap->blocks);
+ memset(heap, 0, sizeof(CollectorHeap));
+}
+
+void Heap::recordExtraCost(size_t cost)
{
// Our frequency of garbage collection tries to balance memory use against speed
// by collecting based on the number of newly created values. However, for values
@@ -175,139 +270,126 @@ void Collector::recordExtraCost(size_t cost)
primaryHeap.extraCost += cost;
}
-template <Collector::HeapType heapType> struct HeapConstants;
+template <HeapType heapType> ALWAYS_INLINE void* Heap::heapAllocate(size_t s)
+{
+ typedef typename HeapConstants<heapType>::Block Block;
+ typedef typename HeapConstants<heapType>::Cell Cell;
-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;
-};
+ 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
-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;
-};
+ 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.
-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);
+ size_t numLiveObjects = heap.numLiveObjects;
+ size_t usedBlocks = heap.usedBlocks;
+ size_t i = heap.firstBlockWithPossibleSpace;
+
+#if COLLECT_ON_EVERY_ALLOCATION
+ collect();
+#endif
+
+ // 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;
+ // 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 {
+ Block* targetBlock;
+ size_t targetBlockUsedCells;
+ if (i != usedBlocks) {
+ targetBlock = reinterpret_cast<Block*>(heap.blocks[i]);
+ targetBlockUsedCells = targetBlock->usedCells;
+ ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock);
+ while (targetBlockUsedCells == HeapConstants<heapType>::cellsPerBlock) {
+ if (++i == usedBlocks)
+ goto collect;
+ targetBlock = reinterpret_cast<Block*>(heap.blocks[i]);
+ targetBlockUsedCells = targetBlock->usedCells;
+ ASSERT(targetBlockUsedCells <= HeapConstants<heapType>::cellsPerBlock);
+ }
+ heap.firstBlockWithPossibleSpace = i;
+ } else {
collect:
- size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
- size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
- const size_t newCost = numNewObjects + heap.extraCost;
+ size_t numLiveObjectsAtLastCollect = heap.numLiveObjectsAtLastCollect;
+ size_t numNewObjects = numLiveObjects - numLiveObjectsAtLastCollect;
+ const size_t newCost = numNewObjects + heap.extraCost;
- if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) {
+ if (newCost >= ALLOCATIONS_PER_COLLECTION && newCost >= numLiveObjectsAtLastCollect) {
#ifndef NDEBUG
- heap.operationInProgress = NoOperation;
+ heap.operationInProgress = NoOperation;
#endif
- bool collected = collect();
+ bool collected = collect();
#ifndef NDEBUG
- heap.operationInProgress = Allocation;
+ heap.operationInProgress = Allocation;
#endif
- if (collected) {
- numLiveObjects = heap.numLiveObjects;
- usedBlocks = heap.usedBlocks;
- i = heap.firstBlockWithPossibleSpace;
- goto scan;
- }
- }
+ 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 *)));
- }
+ // 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;
+ targetBlock = reinterpret_cast<Block*>(allocateBlock<heapType>());
+ targetBlock->freeList = targetBlock->cells;
+ targetBlock->heap = this;
+ targetBlockUsedCells = 0;
+ heap.blocks[usedBlocks] = reinterpret_cast<CollectorBlock*>(targetBlock);
+ heap.usedBlocks = usedBlocks + 1;
+ heap.firstBlockWithPossibleSpace = usedBlocks;
+ }
- // "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;
+ // 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;
+ 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;
+ // FIXME: Consider doing this in NDEBUG builds too (see comment above).
+ heap.operationInProgress = NoOperation;
#endif
- return newCell;
+ return newCell;
}
-void* Collector::allocate(size_t s)
+void* Heap::allocate(size_t s)
{
return heapAllocate<PrimaryHeap>(s);
}
-void* Collector::allocateNumber(size_t s)
+void* Heap::allocateNumber(size_t s)
{
return heapAllocate<NumberHeap>(s);
}
@@ -325,10 +407,10 @@ static inline void* currentThreadStackBase()
MOV EAX, FS:[18h]
MOV pTib, EAX
}
- return (void*)pTib->StackBase;
+ return static_cast<void*>(pTib->StackBase);
#elif PLATFORM(WIN_OS) && PLATFORM(X86_64) && COMPILER(MSVC)
PNT_TIB64 pTib = reinterpret_cast<PNT_TIB64>(NtCurrentTeb());
- return (void*)pTib->StackBase;
+ return reinterpret_cast<void*>(pTib->StackBase);
#elif PLATFORM(WIN_OS) && PLATFORM(X86) && COMPILER(GCC)
// offset 0x18 from the FS segment register gives a pointer to
// the thread information block for the current thread
@@ -336,11 +418,16 @@ static inline void* currentThreadStackBase()
asm ( "movl %%fs:0x18, %0\n"
: "=r" (pTib)
);
- return (void*)pTib->StackBase;
+ return static_cast<void*>(pTib->StackBase);
#elif PLATFORM(SOLARIS)
stack_t s;
thr_stksegment(&s);
return s.ss_sp;
+#elif PLATFORM(OPENBSD)
+ pthread_t thread = pthread_self();
+ stack_t stack;
+ pthread_stackseg_np(thread, &stack);
+ return stack.ss_sp;
#elif PLATFORM(UNIX)
static void* stackBase = 0;
static size_t stackSize = 0;
@@ -368,41 +455,7 @@ static inline void* currentThreadStackBase()
#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
+#if ENABLE(JSC_MULTIPLE_THREADS)
static inline PlatformThread getCurrentPlatformThread()
{
@@ -414,136 +467,127 @@ static inline PlatformThread getCurrentPlatformThread()
#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)
+void Heap::registerThread()
{
- Collector::Thread* thread = (Collector::Thread*)data;
+ if (pthread_getspecific(m_currentThreadRegistrar))
+ return;
- // 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.
- }
+ pthread_setspecific(m_currentThreadRegistrar, this);
+ Heap::Thread* thread = new Heap::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase());
- JSLock::unlock();
+ MutexLocker lock(m_registeredThreadsMutex);
- delete thread;
+ thread->next = m_registeredThreads;
+ m_registeredThreads = thread;
}
-static void initializeRegisteredThreadKey()
+void Heap::unregisterThread(void* p)
{
- pthread_key_create(&registeredThreadKey, destroyRegisteredThread);
+ if (p)
+ static_cast<Heap*>(p)->unregisterThread();
}
-void Collector::registerThread()
+void Heap::unregisterThread()
{
- 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
+ pthread_t currentPosixThread = pthread_self();
+
+ MutexLocker lock(m_registeredThreadsMutex);
+
+ if (pthread_equal(currentPosixThread, m_registeredThreads->posixThread)) {
+ Thread* t = m_registeredThreads;
+ m_registeredThreads = m_registeredThreads->next;
+ delete t;
+ } else {
+ Heap::Thread* last = m_registeredThreads;
+ Heap::Thread* t;
+ for (t = m_registeredThreads->next; t; t = t->next) {
+ if (pthread_equal(t->posixThread, currentPosixThread)) {
+ last->next = t->next;
+ break;
+ }
+ last = t;
+ }
+ ASSERT(t); // If t is NULL, we never found ourselves in the list.
+ delete t;
+ }
+}
- Collector::Thread *thread = new Collector::Thread(pthread_self(), getCurrentPlatformThread(), currentThreadStackBase());
+#else // ENABLE(JSC_MULTIPLE_THREADS)
- thread->next = registeredThreads;
- registeredThreads = thread;
- pthread_setspecific(registeredThreadKey, thread);
- }
+void Heap::registerThread()
+{
}
#endif
-#define IS_POINTER_ALIGNED(p) (((intptr_t)(p) & (sizeof(char *) - 1)) == 0)
+#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)
+void Heap::markConservatively(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;
- }
- }
+ if (start > end) {
+ void* tmp = start;
+ start = end;
+ end = tmp;
+ }
+
+ ASSERT((static_cast<char*>(end) - static_cast<char*>(start)) < 0x1000000);
+ ASSERT(IS_POINTER_ALIGNED(start));
+ ASSERT(IS_POINTER_ALIGNED(end));
+
+ char** p = static_cast<char**>(start);
+ char** e = static_cast<char**>(end);
+
+ size_t usedPrimaryBlocks = primaryHeap.usedBlocks;
+ size_t usedNumberBlocks = numberHeap.usedBlocks;
+ CollectorBlock** primaryBlocks = primaryHeap.blocks;
+ CollectorBlock** numberBlocks = numberHeap.blocks;
+
+ const size_t lastCellOffset = sizeof(CollectorCell) * (CELLS_PER_BLOCK - 1);
+
+ while (p != e) {
+ char* x = *p++;
+ if (IS_HALF_CELL_ALIGNED(x) && x) {
+ uintptr_t xAsBits = reinterpret_cast<uintptr_t>(x);
+ xAsBits &= CELL_ALIGN_MASK;
+ uintptr_t offset = xAsBits & BLOCK_OFFSET_MASK;
+ CollectorBlock* blockAddr = reinterpret_cast<CollectorBlock*>(xAsBits - offset);
+ // Mark the the number heap, we can mark these Cells directly to avoid the virtual call cost
+ for (size_t block = 0; block < usedNumberBlocks; block++) {
+ if ((numberBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
+ Heap::markCell(reinterpret_cast<JSCell*>(xAsBits));
+ goto endMarkLoop;
+ }
+ }
- // Mark the primary heap
- for (size_t block = 0; block < usedPrimaryBlocks; block++) {
- if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
- if (((CollectorCell*)xAsBits)->u.freeCell.zeroIfFree != 0) {
- JSCell* imp = reinterpret_cast<JSCell*>(xAsBits);
- if (!imp->marked())
- imp->mark();
- }
- break;
- }
- }
- endMarkLoop:
- ;
- }
- }
+ // Mark the primary heap
+ for (size_t block = 0; block < usedPrimaryBlocks; block++) {
+ if ((primaryBlocks[block] == blockAddr) & (offset <= lastCellOffset)) {
+ if (reinterpret_cast<CollectorCell*>(xAsBits)->u.freeCell.zeroIfFree != 0) {
+ JSCell* imp = reinterpret_cast<JSCell*>(xAsBits);
+ if (!imp->marked())
+ imp->mark();
+ }
+ break;
+ }
+ }
+ endMarkLoop:
+ ;
+ }
+ }
}
-void Collector::markCurrentThreadConservatively()
+void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal()
+{
+ void* dummy;
+ void* stackPointer = &dummy;
+ void* stackBase = currentThreadStackBase();
+ markConservatively(stackPointer, stackBase);
+}
+
+void Heap::markCurrentThreadConservatively()
{
// setjmp forces volatile registers onto the stack
jmp_buf registers;
@@ -556,43 +600,17 @@ void Collector::markCurrentThreadConservatively()
#pragma warning(pop)
#endif
-#ifdef ANDROID_FIX
- // The code is assuming that dummy is after registers on the stack. BUT it is really compiler
- // dependent. There is no guaranteed correspondence between the stack order and variables
- // declared order. If registers is after dummy in the stack, it won't be marked correctly and
- // GC will free variables which should not be. http://bugs.webkit.org/show_bug.cgi?id=16204
- // is caused by this.
- // To put dummy in a separate function and declare it as noinline, we ensure registers will be
- // marked correctly.
- markCurrentThreadConservativelyEx();
-#else
- void* dummy;
- void* stackPointer = &dummy;
- void* stackBase = currentThreadStackBase();
-
- markStackObjectsConservatively(stackPointer, stackBase);
-#endif
-}
-
-#ifdef ANDROID_FIX
-void Collector::markCurrentThreadConservativelyEx()
-{
- void* dummy;
- void* stackPointer = &dummy;
- void* stackBase = currentThreadStackBase();
-
- markStackObjectsConservatively(stackPointer, stackBase);
+ markCurrentThreadConservativelyInternal();
}
-#endif
-#if USE(MULTIPLE_THREADS)
+#if ENABLE(JSC_MULTIPLE_THREADS)
static inline void suspendThread(const PlatformThread& platformThread)
{
#if PLATFORM(DARWIN)
- thread_suspend(platformThread);
+ thread_suspend(platformThread);
#elif PLATFORM(WIN_OS)
- SuspendThread(platformThread.handle);
+ SuspendThread(platformThread.handle);
#else
#error Need a way to suspend threads on this platform
#endif
@@ -601,9 +619,9 @@ static inline void suspendThread(const PlatformThread& platformThread)
static inline void resumeThread(const PlatformThread& platformThread)
{
#if PLATFORM(DARWIN)
- thread_resume(platformThread);
+ thread_resume(platformThread);
#elif PLATFORM(WIN_OS)
- ResumeThread(platformThread.handle);
+ ResumeThread(platformThread.handle);
#else
#error Need a way to resume threads on this platform
#endif
@@ -613,14 +631,16 @@ typedef unsigned long usword_t; // word size, assumed to be either 32 or 64 bit
#if PLATFORM(DARWIN)
-#if PLATFORM(X86)
+#if PLATFORM(X86)
typedef i386_thread_state_t PlatformThreadRegisters;
-#elif PLATFORM(X86_64)
+#elif PLATFORM(X86_64)
typedef x86_thread_state64_t PlatformThreadRegisters;
-#elif PLATFORM(PPC)
+#elif PLATFORM(PPC)
typedef ppc_thread_state_t PlatformThreadRegisters;
-#elif PLATFORM(PPC64)
+#elif PLATFORM(PPC64)
typedef ppc_thread_state64_t PlatformThreadRegisters;
+#elif PLATFORM(ARM)
+typedef arm_thread_state_t PlatformThreadRegisters;
#else
#error Unknown Architecture
#endif
@@ -635,35 +655,38 @@ size_t getPlatformThreadRegisters(const PlatformThread& platformThread, Platform
{
#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;
+#if PLATFORM(X86)
+ unsigned user_count = sizeof(regs)/sizeof(int);
+ thread_state_flavor_t flavor = i386_THREAD_STATE;
+#elif PLATFORM(X86_64)
+ unsigned user_count = x86_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = x86_THREAD_STATE64;
+#elif PLATFORM(PPC)
+ unsigned user_count = PPC_THREAD_STATE_COUNT;
+ thread_state_flavor_t flavor = PPC_THREAD_STATE;
+#elif PLATFORM(PPC64)
+ unsigned user_count = PPC_THREAD_STATE64_COUNT;
+ thread_state_flavor_t flavor = PPC_THREAD_STATE64;
+#elif PLATFORM(ARM)
+ unsigned user_count = ARM_THREAD_STATE_COUNT;
+ thread_state_flavor_t flavor = ARM_THREAD_STATE;
#else
#error Unknown Architecture
#endif
- kern_return_t result = thread_get_state(platformThread, flavor, (thread_state_t)&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);
+ 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);
+ 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
@@ -676,11 +699,13 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
#if __DARWIN_UNIX03
#if PLATFORM(X86)
- return (void*)regs.__esp;
+ return reinterpret_cast<void*>(regs.__esp);
#elif PLATFORM(X86_64)
- return (void*)regs.__rsp;
+ return reinterpret_cast<void*>(regs.__rsp);
#elif PLATFORM(PPC) || PLATFORM(PPC64)
- return (void*)regs.__r1;
+ return reinterpret_cast<void*>(regs.__r1);
+#elif PLATFORM(ARM)
+ return reinterpret_cast<void*>(regs.__sp);
#else
#error Unknown Architecture
#endif
@@ -688,11 +713,11 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
#else // !__DARWIN_UNIX03
#if PLATFORM(X86)
- return (void*)regs.esp;
+ return reinterpret_cast<void*>(regs.esp);
#elif PLATFORM(X86_64)
- return (void*)regs.rsp;
+ return reinterpret_cast<void*>(regs.rsp);
#elif (PLATFORM(PPC) || PLATFORM(PPC64))
- return (void*)regs.r1;
+ return reinterpret_cast<void*>(regs.r1);
#else
#error Unknown Architecture
#endif
@@ -701,156 +726,139 @@ static inline void* otherThreadStackPointer(const PlatformThreadRegisters& regs)
// end PLATFORM(DARWIN)
#elif PLATFORM(X86) && PLATFORM(WIN_OS)
- return (void*)(uintptr_t)regs.Esp;
+ return reinterpret_cast<void*>((uintptr_t) regs.Esp);
#else
#error Need a way to get the stack pointer for another thread on this platform
#endif
}
-void Collector::markOtherThreadConservatively(Thread* thread)
+void Heap::markOtherThreadConservatively(Thread* thread)
{
- suspendThread(thread->platformThread);
+ suspendThread(thread->platformThread);
+
+ PlatformThreadRegisters regs;
+ size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
- PlatformThreadRegisters regs;
- size_t regSize = getPlatformThreadRegisters(thread->platformThread, regs);
+ // mark the thread's registers
+ markConservatively(static_cast<void*>(&regs), static_cast<void*>(reinterpret_cast<char*>(&regs) + regSize));
- // mark the thread's registers
- markStackObjectsConservatively((void*)&regs, (void*)((char*)&regs + regSize));
-
- void* stackPointer = otherThreadStackPointer(regs);
- markStackObjectsConservatively(stackPointer, thread->stackBase);
+ void* stackPointer = otherThreadStackPointer(regs);
+ markConservatively(stackPointer, thread->stackBase);
- resumeThread(thread->platformThread);
+ resumeThread(thread->platformThread);
}
#endif
-void Collector::markStackObjectsConservatively()
+void Heap::markStackObjectsConservatively()
{
- markCurrentThreadConservatively();
+ markCurrentThreadConservatively();
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+
+ if (m_currentThreadRegistrar) {
+
+ MutexLocker lock(m_registeredThreadsMutex);
-#if USE(MULTIPLE_THREADS)
- for (Thread *thread = registeredThreads; thread != NULL; thread = thread->next) {
- if (!pthread_equal(thread->posixThread, pthread_self())) {
- markOtherThreadConservatively(thread);
+#ifndef NDEBUG
+ // Forbid malloc during the mark phase. Marking a thread suspends it, so
+ // a malloc inside mark() would risk a deadlock with a thread that had been
+ // suspended while holding the malloc lock.
+ fastMallocForbid();
+#endif
+ // It is safe to access the registeredThreads list, because we earlier asserted that locks are being held,
+ // and since this is a shared heap, they are real locks.
+ for (Thread* thread = m_registeredThreads; thread; thread = thread->next) {
+ if (!pthread_equal(thread->posixThread, pthread_self()))
+ markOtherThreadConservatively(thread);
+ }
+#ifndef NDEBUG
+ fastMallocAllow();
+#endif
}
- }
#endif
}
-typedef HashCountedSet<JSCell*> ProtectCountSet;
-
-static ProtectCountSet& protectedValues()
+void Heap::setGCProtectNeedsLocking()
{
- static ProtectCountSet staticProtectCountSet;
- return staticProtectCountSet;
+ // Most clients do not need to call this, with the notable exception of WebCore.
+ // Clients that use shared heap have JSLock protection, while others are supposed
+ // to do explicit locking. WebCore violates this contract in Database code,
+ // which calls gcUnprotect from a secondary thread.
+ if (!m_protectedValuesMutex)
+ m_protectedValuesMutex.set(new Mutex);
}
-void Collector::protect(JSValue *k)
+void Heap::protect(JSValue* k)
{
ASSERT(k);
- ASSERT(JSLock::lockCount() > 0);
- ASSERT(JSLock::currentThreadIsHoldingLock());
+ ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance);
if (JSImmediate::isImmediate(k))
- return;
+ return;
+
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->lock();
+
+ m_protectedValues.add(k->asCell());
- protectedValues().add(k->asCell());
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->unlock();
}
-void Collector::unprotect(JSValue *k)
+void Heap::unprotect(JSValue* k)
{
ASSERT(k);
- ASSERT(JSLock::lockCount() > 0);
- ASSERT(JSLock::currentThreadIsHoldingLock());
+ ASSERT(JSLock::currentThreadIsHoldingLock() || !m_globalData->isSharedInstance);
if (JSImmediate::isImmediate(k))
- return;
-
- protectedValues().remove(k->asCell());
-}
+ return;
-void Collector::collectOnMainThreadOnly(JSValue* value)
-{
- ASSERT(value);
- ASSERT(JSLock::lockCount() > 0);
- ASSERT(JSLock::currentThreadIsHoldingLock());
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->lock();
- if (JSImmediate::isImmediate(value))
- return;
+ m_protectedValues.remove(k->asCell());
- JSCell* cell = value->asCell();
- cellBlock(cell)->collectOnMainThreadOnly.set(cellOffset(cell));
- ++mainThreadOnlyObjectCount;
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->unlock();
}
-void Collector::markProtectedObjects()
+Heap* Heap::heap(JSValue* v)
{
- 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();
- }
+ if (JSImmediate::isImmediate(v))
+ return 0;
+ return Heap::cellBlock(v->asCell())->heap;
}
-void Collector::markMainThreadOnlyObjects()
+void Heap::markProtectedObjects()
{
-#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;
- }
- }
- }
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->lock();
+
+ ProtectCountSet::iterator end = m_protectedValues.end();
+ for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) {
+ JSCell* val = it->first;
+ if (!val->marked())
+ val->mark();
}
+
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->unlock();
}
-template <Collector::HeapType heapType> size_t Collector::sweep(bool currentThreadIsMainThread)
+template <HeapType heapType> size_t Heap::sweep()
{
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;
+ CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap;
size_t emptyBlocks = 0;
size_t numLiveObjects = heap.numLiveObjects;
for (size_t block = 0; block < heap.usedBlocks; block++) {
- Block* curBlock = (Block*)heap.blocks[block];
+ Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]);
size_t usedCells = curBlock->usedCells;
Cell* freeList = curBlock->freeList;
@@ -861,7 +869,7 @@ template <Collector::HeapType heapType> size_t Collector::sweep(bool currentThre
if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) {
Cell* cell = curBlock->cells + i;
- if (heapType != Collector::NumberHeap) {
+ if (heapType != NumberHeap) {
JSCell* imp = reinterpret_cast<JSCell*>(cell);
// special case for allocated but uninitialized object
// (We don't need this check earlier because nothing prior this point
@@ -869,11 +877,6 @@ template <Collector::HeapType heapType> size_t Collector::sweep(bool currentThre
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();
}
@@ -889,18 +892,13 @@ template <Collector::HeapType heapType> size_t Collector::sweep(bool currentThre
} else {
size_t minimumCellsToProcess = usedCells;
for (size_t i = 0; (i < minimumCellsToProcess) & (i < HeapConstants<heapType>::cellsPerBlock); i++) {
- Cell *cell = curBlock->cells + 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;
- }
+ if (heapType != NumberHeap) {
+ JSCell* imp = reinterpret_cast<JSCell*>(cell);
imp->~JSCell();
}
--usedCells;
@@ -923,7 +921,7 @@ template <Collector::HeapType heapType> size_t Collector::sweep(bool currentThre
emptyBlocks++;
if (emptyBlocks > SPARE_EMPTY_BLOCKS) {
#if !DEBUG_COLLECTOR
- freeBlock((CollectorBlock*)curBlock);
+ freeBlock(reinterpret_cast<CollectorBlock*>(curBlock));
#endif
// swap with the last block so we compact as we go
heap.blocks[block] = heap.blocks[heap.usedBlocks - 1];
@@ -932,7 +930,7 @@ template <Collector::HeapType heapType> size_t Collector::sweep(bool currentThre
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 *));
+ heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock*)));
}
}
}
@@ -947,145 +945,150 @@ template <Collector::HeapType heapType> size_t Collector::sweep(bool currentThre
return numLiveObjects;
}
-bool Collector::collect()
+bool Heap::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;
+#ifndef NDEBUG
+ if (m_globalData->isSharedInstance) {
+ ASSERT(JSLock::lockCount() > 0);
+ ASSERT(JSLock::currentThreadIsHoldingLock());
+ }
+#endif
- bool currentThreadIsMainThread = onMainThread();
+ ASSERT((primaryHeap.operationInProgress == NoOperation) | (numberHeap.operationInProgress == NoOperation));
+ if ((primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation))
+ abort();
+
+ JAVASCRIPTCORE_GC_BEGIN();
+ primaryHeap.operationInProgress = Collection;
+ numberHeap.operationInProgress = Collection;
+
+ // MARK: first mark all referenced objects recursively starting out from the set of root objects
+
+ markStackObjectsConservatively();
+ markProtectedObjects();
+ if (m_markListSet && m_markListSet->size())
+ ArgList::markLists(*m_markListSet);
+ if (m_globalData->exception && !m_globalData->exception->marked())
+ m_globalData->exception->mark();
+ m_globalData->machine->registerFile().markCallFrames(this);
+ m_globalData->smallStrings.mark();
+
+ JSGlobalObject* globalObject = m_globalData->head;
+ if (globalObject) {
+ do {
+ globalObject->markCrossHeapDependentObjects();
+ globalObject = globalObject->next();
+ } while (globalObject != m_globalData->head);
+ }
- // MARK: first mark all referenced objects recursively starting out from the set of root objects
+ JAVASCRIPTCORE_GC_MARKED();
-#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
+ size_t originalLiveObjects = primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
+ size_t numLiveObjects = sweep<PrimaryHeap>();
+ numLiveObjects += sweep<NumberHeap>();
- markStackObjectsConservatively();
- markProtectedObjects();
- ExecState::markActiveExecStates();
- List::markProtectedLists();
-#if USE(MULTIPLE_THREADS)
- if (!currentThreadIsMainThread)
- markMainThreadOnlyObjects();
-#endif
+ primaryHeap.operationInProgress = NoOperation;
+ numberHeap.operationInProgress = NoOperation;
+ JAVASCRIPTCORE_GC_END(originalLiveObjects, numLiveObjects);
-#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;
+ return numLiveObjects < originalLiveObjects;
}
-size_t Collector::size()
+size_t Heap::size()
{
- return primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
+ return primaryHeap.numLiveObjects + numberHeap.numLiveObjects;
}
-size_t Collector::globalObjectCount()
+size_t Heap::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 count = 0;
+ if (JSGlobalObject* head = m_globalData->head) {
+ JSGlobalObject* o = head;
+ do {
+ ++count;
+ o = o->next();
+ } while (o != head);
+ }
+ return count;
}
-size_t Collector::protectedGlobalObjectCount()
+size_t Heap::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;
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->lock();
+
+ size_t count = 0;
+ if (JSGlobalObject* head = m_globalData->head) {
+ JSGlobalObject* o = head;
+ do {
+ if (m_protectedValues.contains(o))
+ ++count;
+ o = o->next();
+ } while (o != head);
+ }
+
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->unlock();
+
+ return count;
}
-size_t Collector::protectedObjectCount()
+size_t Heap::protectedObjectCount()
{
- return protectedValues().size();
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->lock();
+
+ size_t result = m_protectedValues.size();
+
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->unlock();
+
+ return result;
}
-static const char *typeName(JSCell *val)
+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;
+ if (val->isString())
+ return "string";
+ if (val->isNumber())
+ return "number";
+ if (val->isGetterSetter())
+ return "gettersetter";
+ ASSERT(val->isObject());
+ const ClassInfo* info = static_cast<JSObject*>(val)->classInfo();
+ return info ? info->className : "Object";
}
-HashCountedSet<const char*>* Collector::protectedObjectTypeCounts()
+HashCountedSet<const char*>* Heap::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)
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->lock();
+
+ ProtectCountSet::iterator end = m_protectedValues.end();
+ for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it)
counts->add(typeName(it->first));
+ if (m_protectedValuesMutex)
+ m_protectedValuesMutex->unlock();
+
return counts;
}
-bool Collector::isBusy()
+bool Heap::isBusy()
{
return (primaryHeap.operationInProgress != NoOperation) | (numberHeap.operationInProgress != NoOperation);
}
-void Collector::reportOutOfMemoryToAllExecStates()
+Heap::iterator Heap::primaryHeapBegin()
{
- 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"));
- }
+ return iterator(primaryHeap.blocks, primaryHeap.blocks + primaryHeap.usedBlocks);
+}
+
+Heap::iterator Heap::primaryHeapEnd()
+{
+ return iterator(primaryHeap.blocks + primaryHeap.usedBlocks, primaryHeap.blocks + primaryHeap.usedBlocks);
}
-} // namespace KJS
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/collector.h b/JavaScriptCore/kjs/collector.h
index 3068d00..4233b06 100644
--- a/JavaScriptCore/kjs/collector.h
+++ b/JavaScriptCore/kjs/collector.h
@@ -1,9 +1,7 @@
-// -*- 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.
+ * 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
@@ -24,180 +22,258 @@
#ifndef KJSCOLLECTOR_H_
#define KJSCOLLECTOR_H_
+#include "JSImmediate.h"
#include <string.h>
#include <wtf/HashCountedSet.h>
+#include <wtf/HashSet.h>
+#include <wtf/Noncopyable.h>
+#include <wtf/OwnPtr.h>
+#include <wtf/Threading.h>
-#ifdef ANDROID_FIX
-#if COMPILER(GCC)
-#define KJS_NO_INLINE __attribute__((noinline))
-#else
-#define KJS_NO_INLINE
+// This is supremely lame that we require pthreads to build on windows.
+#if ENABLE(JSC_MULTIPLE_THREADS)
+#include <pthread.h>
#endif
-#endif // ANDROID_FIX
-namespace KJS {
+#define ASSERT_CLASS_FITS_IN_CELL(class) COMPILE_ASSERT(sizeof(class) <= CELL_SIZE, class_fits_in_cell)
- class JSCell;
- class JSValue;
- class CollectorBlock;
+namespace JSC {
- 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
+ class ArgList;
+ class CollectorBlock;
+ class JSCell;
+ class JSGlobalData;
- static const size_t minExtraCostSize = 256;
+ enum OperationInProgress { NoOperation, Allocation, Collection };
+ enum HeapType { PrimaryHeap, NumberHeap };
- static void reportExtraMemoryCost(size_t cost);
+ template <HeapType> class CollectorHeapIterator;
- static size_t size();
+ struct CollectorHeap {
+ CollectorBlock** blocks;
+ size_t numBlocks;
+ size_t usedBlocks;
+ size_t firstBlockWithPossibleSpace;
- static void protect(JSValue*);
- static void unprotect(JSValue*);
-
- static void collectOnMainThreadOnly(JSValue*);
+ size_t numLiveObjects;
+ size_t numLiveObjectsAtLastCollect;
+ size_t extraCost;
- static size_t globalObjectCount();
- static size_t protectedObjectCount();
- static size_t protectedGlobalObjectCount();
- static HashCountedSet<const char*>* protectedObjectTypeCounts();
+ OperationInProgress operationInProgress;
+ };
- class Thread;
- static void registerThread();
-
- static void registerAsMainThread();
+ class Heap : Noncopyable {
+ public:
+ class Thread;
+ typedef CollectorHeapIterator<PrimaryHeap> iterator;
- static bool isCellMarked(const JSCell*);
- static void markCell(JSCell*);
+ void destroy();
- enum HeapType { PrimaryHeap, NumberHeap };
+#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE
+ // We can inline these functions because everything is compiled as
+ // one file, so the heapAllocate template definitions are available.
+ // However, allocateNumber is used via jsNumberCell outside JavaScriptCore.
+ // Thus allocateNumber needs to provide a non-inline version too.
+ void* inlineAllocateNumber(size_t s) { return heapAllocate<NumberHeap>(s); }
+ void* inlineAllocate(size_t s) { return heapAllocate<PrimaryHeap>(s); }
+#endif
+ void* allocateNumber(size_t);
+ void* allocate(size_t);
+
+ bool collect();
+ bool isBusy(); // true if an allocation or collection is in progress
+
+ static const size_t minExtraCostSize = 256;
+
+ void reportExtraMemoryCost(size_t cost);
+
+ size_t size();
+
+ void setGCProtectNeedsLocking();
+ void protect(JSValue*);
+ void unprotect(JSValue*);
+
+ static Heap* heap(JSValue*); // 0 for immediate values
+
+ size_t globalObjectCount();
+ size_t protectedObjectCount();
+ size_t protectedGlobalObjectCount();
+ HashCountedSet<const char*>* protectedObjectTypeCounts();
+
+ void registerThread(); // Only needs to be called by clients that can use the same heap from multiple threads.
+
+ static bool isCellMarked(const JSCell*);
+ static void markCell(JSCell*);
+
+ void markConservatively(void* start, void* end);
+
+ HashSet<ArgList*>& markListSet() { if (!m_markListSet) m_markListSet = new HashSet<ArgList*>; return *m_markListSet; }
+
+ JSGlobalData* globalData() const { return m_globalData; }
+ static bool isNumber(JSCell*);
+
+ // Iterators for the object heap.
+ iterator primaryHeapBegin();
+ iterator primaryHeapEnd();
+
+ private:
+ template <HeapType heapType> void* heapAllocate(size_t);
+ template <HeapType heapType> size_t sweep();
+ static CollectorBlock* cellBlock(const JSCell*);
+ static size_t cellOffset(const JSCell*);
+
+ friend class JSGlobalData;
+ Heap(JSGlobalData*);
+ ~Heap();
+
+ void recordExtraCost(size_t);
+ void markProtectedObjects();
+ void markCurrentThreadConservatively();
+ void markCurrentThreadConservativelyInternal();
+ void markOtherThreadConservatively(Thread*);
+ void markStackObjectsConservatively();
+
+ typedef HashCountedSet<JSCell*> ProtectCountSet;
+
+ CollectorHeap primaryHeap;
+ CollectorHeap numberHeap;
- 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();
-#ifdef ANDROID_FIX
- static void markCurrentThreadConservativelyEx() KJS_NO_INLINE;
+ OwnPtr<Mutex> m_protectedValuesMutex; // Only non-null if the client explicitly requested it via setGCPrtotectNeedsLocking().
+ ProtectCountSet m_protectedValues;
+
+ HashSet<ArgList*>* m_markListSet;
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ static void unregisterThread(void*);
+ void unregisterThread();
+
+ Mutex m_registeredThreadsMutex;
+ Thread* m_registeredThreads;
+ pthread_key_t m_currentThreadRegistrar;
#endif
- 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);
+
+ JSGlobalData* m_globalData;
+ };
+
+ // tunable parameters
+ template<size_t bytesPerWord> struct CellSize;
+
+ // cell size needs to be a power of two for certain optimizations in collector.cpp
+ template<> struct CellSize<sizeof(uint32_t)> { static const size_t m_value = 32; }; // 32-bit
+ template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; }; // 64-bit
+ const size_t BLOCK_SIZE = 16 * 4096; // 64k
+
+ // derived constants
+ const size_t BLOCK_OFFSET_MASK = BLOCK_SIZE - 1;
+ const size_t BLOCK_MASK = ~BLOCK_OFFSET_MASK;
+ const size_t MINIMUM_CELL_SIZE = CellSize<sizeof(void*)>::m_value;
+ const size_t CELL_ARRAY_LENGTH = (MINIMUM_CELL_SIZE / sizeof(double)) + (MINIMUM_CELL_SIZE % sizeof(double) != 0 ? sizeof(double) : 0);
+ const size_t CELL_SIZE = CELL_ARRAY_LENGTH * sizeof(double);
+ const size_t SMALL_CELL_SIZE = CELL_SIZE / 2;
+ const size_t CELL_MASK = CELL_SIZE - 1;
+ const size_t CELL_ALIGN_MASK = ~CELL_MASK;
+ const size_t CELLS_PER_BLOCK = (BLOCK_SIZE * 8 - sizeof(uint32_t) * 8 - sizeof(void *) * 8 - 2 * (7 + 3 * 8)) / (CELL_SIZE * 8 + 2);
+ const size_t SMALL_CELLS_PER_BLOCK = 2 * CELLS_PER_BLOCK;
+ const size_t BITMAP_SIZE = (CELLS_PER_BLOCK + 7) / 8;
+ const size_t BITMAP_WORDS = (BITMAP_SIZE + 3) / sizeof(uint32_t);
- struct CollectorBitmap {
- uint32_t bits[BITMAP_WORDS];
- bool get(size_t n) const { return !!(bits[n >> 5] & (1 << (n & 0x1F))); }
- void set(size_t n) { bits[n >> 5] |= (1 << (n & 0x1F)); }
- void clear(size_t n) { bits[n >> 5] &= ~(1 << (n & 0x1F)); }
- void clearAll() { memset(bits, 0, sizeof(bits)); }
- };
+ struct 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;
- };
-
- 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
+ struct CollectorCell {
+ union {
+ double memory[CELL_ARRAY_LENGTH];
+ struct {
+ void* zeroIfFree;
+ ptrdiff_t next;
+ } freeCell;
+ } u;
+ };
+
+ struct SmallCollectorCell {
+ union {
+ double memory[CELL_ARRAY_LENGTH / 2];
+ struct {
+ void* zeroIfFree;
+ ptrdiff_t next;
+ } freeCell;
+ } u;
+ };
+
+ class CollectorBlock {
+ public:
+ CollectorCell cells[CELLS_PER_BLOCK];
+ uint32_t usedCells;
+ CollectorCell* freeList;
+ CollectorBitmap marked;
+ Heap* heap;
+ HeapType type;
+ };
+
+ class SmallCellCollectorBlock {
+ public:
+ SmallCollectorCell cells[SMALL_CELLS_PER_BLOCK];
+ uint32_t usedCells;
+ SmallCollectorCell* freeList;
+ CollectorBitmap marked;
+ Heap* heap;
+ HeapType type;
+ };
+
+ template <HeapType heapType> struct HeapConstants;
+
+ template <> struct HeapConstants<PrimaryHeap> {
+ static const size_t cellSize = CELL_SIZE;
+ static const size_t cellsPerBlock = CELLS_PER_BLOCK;
+ static const size_t bitmapShift = 0;
+ typedef CollectorCell Cell;
+ typedef CollectorBlock Block;
+ };
+
+ template <> struct HeapConstants<NumberHeap> {
+ static const size_t cellSize = SMALL_CELL_SIZE;
+ static const size_t cellsPerBlock = SMALL_CELLS_PER_BLOCK;
+ static const size_t bitmapShift = 1;
+ typedef SmallCollectorCell Cell;
+ typedef SmallCellCollectorBlock Block;
+ };
+
+ inline CollectorBlock* Heap::cellBlock(const JSCell* cell)
+ {
+ return reinterpret_cast<CollectorBlock*>(reinterpret_cast<uintptr_t>(cell) & BLOCK_MASK);
+ }
+
+ inline bool Heap::isNumber(JSCell* cell)
+ {
+ return Heap::cellBlock(cell)->type == NumberHeap;
+ }
+
+ inline size_t Heap::cellOffset(const JSCell* cell)
+ {
+ return (reinterpret_cast<uintptr_t>(cell) & BLOCK_OFFSET_MASK) / CELL_SIZE;
+ }
+
+ inline bool Heap::isCellMarked(const JSCell* cell)
+ {
+ return cellBlock(cell)->marked.get(cellOffset(cell));
+ }
+
+ inline void Heap::markCell(JSCell* cell)
+ {
+ cellBlock(cell)->marked.set(cellOffset(cell));
+ }
+
+ inline void Heap::reportExtraMemoryCost(size_t cost)
+ {
+ if (cost > minExtraCostSize)
+ recordExtraCost(cost / (CELL_SIZE * 2));
+ }
+
+} // namespace JSC
#endif /* KJSCOLLECTOR_H_ */
diff --git a/JavaScriptCore/kjs/completion.h b/JavaScriptCore/kjs/completion.h
index 09f3db7..56d13ed 100644
--- a/JavaScriptCore/kjs/completion.h
+++ b/JavaScriptCore/kjs/completion.h
@@ -1,4 +1,3 @@
-// -*- c-basic-offset: 2 -*-
/*
* Copyright (C) 1999-2001 Harri Porten (porten@kde.org)
* Copyright (C) 2001 Peter Kelly (pmk@post.com)
@@ -24,37 +23,34 @@
#ifndef KJS_COMPLETION_H
#define KJS_COMPLETION_H
-namespace KJS {
+#include "JSValue.h"
- class JSValue;
+namespace JSC {
- enum ComplType { Normal, Break, Continue, ReturnValue, Throw, Interrupted };
+ 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) { }
+ /*
+ * Completion objects are used to convey the return status and value
+ * from functions.
+ */
+ class Completion {
+ public:
+ Completion(ComplType type = Normal, JSValue* value = noValue())
+ : 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; }
+ 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;
- };
+ private:
+ ComplType m_type;
+ JSValue* m_value;
+ };
-}
+} // namespace JSC
-#endif
+#endif // KJS_COMPLETION_H
diff --git a/JavaScriptCore/kjs/config.h b/JavaScriptCore/kjs/config.h
index fd2779b..80a3798 100644
--- a/JavaScriptCore/kjs/config.h
+++ b/JavaScriptCore/kjs/config.h
@@ -1,5 +1,5 @@
/*
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2006, 2007, 2008 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
@@ -19,40 +19,19 @@
*
*/
-#include <wtf/Platform.h>
-
-#if PLATFORM(MAC)
-#define HAVE_JNI 1
+#if defined(HAVE_CONFIG_H) && HAVE_CONFIG_H
+#include "autotoolsconfig.h"
#endif
-#ifdef ANDROID
+#include <wtf/Platform.h>
-#define HAVE_JNI 1
-#define HAVE_FUNC_FINITE 1
-#define HAVE_MMAP 1
-#define HAVE_STRINGS_H 1
-#define HAVE_SYS_TIME_H 1
-#define HAVE_SYS_PARAM_H 1
-#define HAVE_ERRNO_H 1
-#define HAVE_SBRK 1
+#if PLATFORM(ANDROID)
#define ANDROID_MOBILE // change can be merged back to WebKit.org for MOBILE
//#define ANDROID_INSTRUMENT
+#endif
-#define ANDROID_FIX // changes can be merged back, or already in, WebKit.org's ToT
-
-#elif 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 PLATFORM(WIN_OS)
// If we don't define these, they get defined in windef.h.
// We want to use std::min and std::max
@@ -66,24 +45,9 @@
#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)
+#if PLATFORM(FREEBSD) || PLATFORM(OPENBSD)
#define HAVE_PTHREAD_NP_H 1
#endif
diff --git a/JavaScriptCore/kjs/create_hash_table b/JavaScriptCore/kjs/create_hash_table
index 6800722..829a024 100755
--- a/JavaScriptCore/kjs/create_hash_table
+++ b/JavaScriptCore/kjs/create_hash_table
@@ -40,66 +40,80 @@ 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 @values = ();
my @hashes = ();
-my @table = ();
-my @links = ();
my $inside = 0;
my $name;
my $size;
-my $hashSizeMask;
my $banner = 0;
-sub calcTable();
+sub calcSize();
sub output();
+sub jsc_ucfirst($);
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";
- }
+ chomp;
+ s/^\s+//;
+ next if /^\#|^$/; # Comment or blank line. Do nothing.
+ if (/^\@begin/ && !$inside) {
+ if (/^\@begin\s*([:_\w]+)\s*\d*\s*$/) {
+ $inside = 1;
+ $name = $1;
+ } else {
+ print STDERR "WARNING: \@begin without table name, skipping $_\n";
+ }
} elsif (/^\@end\s*$/ && $inside) {
+ calcSize();
+ output();
- calcTable();
-
- output();
- @keys = ();
- @values = ();
- @attrs = ();
- @params = ();
- @table = ();
- @links = ();
- @hashes = ();
- $inside = 0;
+ @keys = ();
+ @attrs = ();
+ @values = ();
+ @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");
+ my $key = $1;
+ my $val = $2;
+ my $att = $3;
+ my $param = $4;
+
+ push(@keys, $key);
+ push(@attrs, length($att) > 0 ? $att : "0");
+
+ if ($att =~ m/Function/) {
+ push(@values, { "type" => "Function", "function" => $val, "params" => (length($param) ? $param : "") });
+ #printf STDERR "WARNING: Number of arguments missing for $key/$val\n" if (length($param) == 0);
+ } elsif (length($att)) {
+ my $get = $val;
+ my $put = !($att =~ m/ReadOnly/) ? "set" . jsc_ucfirst($val) : "0";
+ push(@values, { "type" => "Property", "get" => $get, "put" => $put });
+ } else {
+ push(@values, { "type" => "Lexer", "value" => $val });
+ }
+ push(@hashes, hashValue($key));
} elsif ($inside) {
- die "invalid data {" . $_ . "}";
+ die "invalid data {" . $_ . "}";
}
}
die "missing closing \@end" if ($inside);
+sub jsc_ucfirst($)
+{
+ my ($value) = @_;
+
+ if ($value =~ /js/) {
+ $value =~ s/js/JS/;
+ return $value;
+ }
+
+ return ucfirst($value);
+}
+
+
sub ceilingToPowerOf2
{
my ($size) = @_;
@@ -112,36 +126,18 @@ sub ceilingToPowerOf2
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++;
- }
+sub calcSize()
+{
+tableSizeLoop:
+ for ($size = ceilingToPowerOf2(scalar @keys); ; $size += $size) {
+ my @table = ();
+ foreach my $key (@keys) {
+ my $h = hashValue($key) % $size;
+ next tableSizeLoop if $table[$h];
+ $table[$h] = 1;
+ }
+ last;
}
- $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($$) {
@@ -203,48 +199,44 @@ sub hashValue($) {
}
sub output() {
- if (!$banner) {
- $banner = 1;
- print "/* Automatically generated from $file using $0. DO NOT EDIT ! */\n";
- }
+ if (!$banner) {
+ $banner = 1;
+ print "// Automatically generated from $file using $0. DO NOT EDIT!\n";
+ }
- my $nameEntries = "${name}Entries";
- $nameEntries =~ s/:/_/g;
+ my $nameEntries = "${name}Values";
+ $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 "\n#include \"lookup.h\"\n" if ($includelookup);
+ if ($useNameSpace) {
+ print "\nnamespace ${useNameSpace} {\n";
+ print "\nusing namespace JSC;\n";
+ } else {
+ print "\nnamespace JSC {\n";
+ }
+ my $count = scalar @keys + 1;
+ print "\nstatic const struct HashTableValue ${nameEntries}\[$count\] = {\n";
+ my $i = 0;
+ foreach my $key (@keys) {
+ my $firstValue = "";
+ my $secondValue = "";
+
+ if ($values[$i]{"type"} eq "Function") {
+ $firstValue = $values[$i]{"function"};
+ $secondValue = $values[$i]{"params"};
+ } elsif ($values[$i]{"type"} eq "Property") {
+ $firstValue = $values[$i]{"get"};
+ $secondValue = $values[$i]{"put"};
+ } elsif ($values[$i]{"type"} eq "Lexer") {
+ $firstValue = $values[$i]{"value"};
+ $secondValue = "0";
}
- print "/* " . $hashes[$entry] . " */ ";
- } else {
- print " { 0, { 0 }, 0, 0, 0 }";
- }
- print "," unless ($i == $size - 1);
- print "\n";
- $i++;
+ print " { \"$key\", $attrs[$i], (intptr_t)$firstValue, (intptr_t)$secondValue },\n";
+ $i++;
}
-
- print "};\n\n";
- print "const struct HashTable $name = ";
- print "\{ 3, $size, $nameEntries, $hashSizeMask \};\n\n";
- print "} // namespace\n";
+ print " { 0, 0, 0, 0 }\n";
+ print "};\n\n";
+ print "extern const struct HashTable $name = ";
+ print "\{ ", $size - 1, ", $nameEntries, 0 \};\n\n";
+ print "} // namespace\n";
}
diff --git a/JavaScriptCore/kjs/date_object.cpp b/JavaScriptCore/kjs/date_object.cpp
deleted file mode 100644
index 6b757c2..0000000
--- a/JavaScriptCore/kjs/date_object.cpp
+++ /dev/null
@@ -1,1615 +0,0 @@
-/*
- * 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 void fillStructuresUsingTimeArgs(ExecState* exec, const List& args, int maxArgs, double* ms, GregorianDateTime* t)
-{
- double milliseconds = 0;
- 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) * msPerHour;
- }
-
- // minutes
- if (maxArgs >= 3 && idx < numArgs) {
- t->minute = 0;
- milliseconds += args[idx++]->toInt32(exec) * msPerMinute;
- }
-
- // seconds
- if (maxArgs >= 2 && idx < numArgs) {
- t->second = 0;
- milliseconds += args[idx++]->toInt32(exec) * msPerSecond;
- }
-
- // milliseconds
- if (idx < numArgs)
- milliseconds += args[idx]->toNumber(exec);
- else
- milliseconds += *ms;
-
- *ms = milliseconds;
-}
-
-// 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 void fillStructuresUsingDateArgs(ExecState *exec, const List &args, int maxArgs, double *ms, GregorianDateTime *t)
-{
- int idx = 0;
- 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) - 1900;
-
- // months
- if (maxArgs >= 2 && idx < numArgs)
- t->month = args[idx++]->toInt32(exec);
-
- // days
- if (idx < numArgs) {
- t->monthDay = 0;
- *ms += args[idx]->toInt32(exec) * msPerDay;
- }
-}
-
-// ------------------------------ 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;
- memset(&t, 0, sizeof(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;
- memset(&t, 0, sizeof(tm));
- 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);
- double secs = floor(milli / msPerSecond);
- double ms = milli - secs * msPerSecond;
-
- GregorianDateTime t;
- msToGregorianDateTime(milli, inputIsUTC, t);
-
- fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t);
-
- 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);
- JSValue* v = thisDateObj->internalValue();
- double milli = v->toNumber(exec);
- double secs = floor(milli / msPerSecond);
- double ms = milli - secs * msPerSecond;
-
- GregorianDateTime t;
- msToGregorianDateTime(milli, inputIsUTC, t);
-
- fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t);
-
- 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);
- JSValue* v = thisDateObj->internalValue();
- double milli = v->toNumber(exec);
- double secs = floor(milli / msPerSecond);
- double ms = milli - secs * msPerSecond;
-
- GregorianDateTime t;
- msToGregorianDateTime(milli, utc, t);
-
- t.year = (args[0]->toInt32(exec) > 99 || args[0]->toInt32(exec) < 0) ? args[0]->toInt32(exec) - 1900 : args[0]->toInt32(exec);
-
- 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);
-
- // IE returns the full year even in getYear.
- if (exec->dynamicGlobalObject()->compatMode() == IECompat)
- return jsNumber(1900 + t.year);
- return jsNumber(t.year);
-}
-
-} // namespace KJS
diff --git a/JavaScriptCore/kjs/date_object.h b/JavaScriptCore/kjs/date_object.h
deleted file mode 100644
index c545980..0000000
--- a/JavaScriptCore/kjs/date_object.h
+++ /dev/null
@@ -1,135 +0,0 @@
-/*
- * 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
deleted file mode 100644
index af9c5fa..0000000
--- a/JavaScriptCore/kjs/debugger.cpp
+++ /dev/null
@@ -1,134 +0,0 @@
-// -*- 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
deleted file mode 100644
index 2d5cb6f..0000000
--- a/JavaScriptCore/kjs/debugger.h
+++ /dev/null
@@ -1,225 +0,0 @@
-// -*- 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
index bee701a..2dc2cff 100644
--- a/JavaScriptCore/kjs/dtoa.cpp
+++ b/JavaScriptCore/kjs/dtoa.cpp
@@ -3,6 +3,7 @@
* The author of this software is David M. Gay.
*
* Copyright (c) 1991, 2000, 2001 by Lucent Technologies.
+ * Copyright (C) 2002, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
@@ -18,26 +19,26 @@
***************************************************************/
/* 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
+ 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);
+ * _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.
+/* strtod for IEEE-arithmetic machines.
*
* This strtod returns a nearest machine number to the input decimal
* string (or sets errno to ERANGE). With IEEE arithmetic, ties are
@@ -49,128 +50,102 @@
*
* 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).
+ * 1. We only require IEEE.
+ * 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.
+ * 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).
+ * significant byte has the lowest address.
* #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.
+ * computation of dtoa.
* #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.
+ * and Honor_FLT_ROUNDS is not #defined.
* #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.
+ * products but inaccurate quotients, e.g., for Intel i860.
+ * #define USE_LONG_LONG on machines that have a "long long"
+ * integer type (of >= 64 bits), and performance testing shows that
+ * it is faster than 32-bit fallback (which is often not the case
+ * on 32-bit machines). On such machines, you can #define Just_16
+ * to store 16 bits per 32-bit int32_t when doing high-precision integer
+ * arithmetic. Whether this speeds things up or slows things down
+ * depends on the machine and the number being converted.
* #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 some or all of DBL_DIG, DBL_MAX_10_EXP, DBL_MAX_EXP,
+ * FLT_RADIX, FLT_ROUNDS, and DBL_MAX.
* #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.
+ * 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 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.
+ * 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).
+ * 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).
+ * 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.
+ * the result overflows to +-Infinity or underflows to 0.
*/
#include "config.h"
#include "dtoa.h"
+#include <errno.h>
+#include <float.h>
+#include <math.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+#include <wtf/AlwaysInline.h>
+#include <wtf/Assertions.h>
+#include <wtf/FastMalloc.h>
+#include <wtf/Threading.h>
+
#if COMPILER(MSVC)
#pragma warning(disable: 4244)
#pragma warning(disable: 4245)
@@ -182,124 +157,34 @@
// http://lists.debian.org/debian-arm/2003/11/msg00008.html
#if PLATFORM(BIG_ENDIAN) || PLATFORM(MIDDLE_ENDIAN)
#define IEEE_MC68k
+#elif PLATFORM(MIDDLE_ENDIAN)
+#define IEEE_ARM
#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
+#define INFNAN_CHECK
-#ifdef __cplusplus
-extern "C" {
+#if defined(IEEE_8087) + defined(IEEE_MC68k) + defined(IEEE_ARM) != 1
+Exactly one of IEEE_8087, IEEE_ARM or IEEE_MC68k should be defined.
#endif
-#ifndef CONST_
-#ifdef KR_headers
-#define CONST_ /* blank */
-#else
-#define CONST_ const
-#endif
-#endif
+namespace JSC {
-#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.
+#if ENABLE(JSC_MULTIPLE_THREADS)
+Mutex* s_dtoaP5Mutex;
#endif
-typedef union { double d; ULong L[2]; } U;
+typedef union { double d; uint32_t 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]
+#define word0(x) ((uint32_t*)&x)[1]
+#define word1(x) ((uint32_t*)&x)[0]
#else
-#define word0(x) ((ULong *)&x)[0]
-#define word1(x) ((ULong *)&x)[1]
+#define word0(x) ((uint32_t*)&x)[0]
+#define word1(x) ((uint32_t*)&x)[1]
#endif
#else
#ifdef IEEE_8087
@@ -316,21 +201,12 @@ typedef union { double d; ULong L[2]; } U;
* 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++)
+#if defined(IEEE_8087) || defined(IEEE_ARM)
+#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++)
+#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
@@ -355,1099 +231,780 @@ typedef union { double d; ULong L[2]; } U;
#define Tiny1 1
#define Quick_max 14
#define Int_max 14
-#ifndef NO_IEEE_Scale
+
+#if !defined(NO_IEEE_Scale)
+#undef Avoid_Underflow
#define Avoid_Underflow
-#ifdef Flush_Denorm /* debugging option */
-#undef Sudden_Underflow
-#endif
#endif
-#ifndef Flt_Rounds
-#ifdef FLT_ROUNDS
+#if !defined(Flt_Rounds)
+#if defined(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 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
+#if PLATFORM(PPC64) || PLATFORM(X86_64)
+// 64-bit emulation provided by the compiler is likely to be slower than dtoa own code on 32-bit hardware.
+#define USE_LONG_LONG
#endif
-#ifdef NO_LONG_LONG
-#undef ULLong
+#ifndef USE_LONG_LONG
#ifdef Just_16
#undef Pack_32
-/* When Pack_32 is not defined, we store 16 bits per 32-bit Long.
+/* When Pack_32 is not defined, we store 16 bits per 32-bit int32_t.
* 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.
+ * slower. Hence the default is now to store 32 bits per int32_t.
*/
#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;
+struct Bigint {
+ struct Bigint* next;
+ int k, maxwds, sign, wds;
+ uint32_t x[1];
+};
- static Bigint *freelist[Kmax+1];
-
- static Bigint *
-Balloc
-#ifdef KR_headers
- (k) int k;
-#else
- (int k)
-#endif
+static Bigint* Balloc(int k)
{
- 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
+ int x = 1 << k;
+ Bigint* rv = (Bigint*)fastMalloc(sizeof(Bigint) + (x - 1)*sizeof(uint32_t));
+ rv->k = k;
+ rv->maxwds = x;
+ rv->next = 0;
+ rv->sign = rv->wds = 0;
+
+ return rv;
+}
+
+static void Bfree(Bigint* v)
{
- 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
+ fastFree(v);
+}
+
+#define Bcopy(x, y) memcpy((char*)&x->sign, (char*)&y->sign, y->wds * sizeof(int32_t) + 2 * sizeof(int))
+
+static Bigint* multadd(Bigint* b, int m, int a) /* multiply by m and add a */
{
- int i, wds;
-#ifdef ULLong
- ULong *x;
- ULLong carry, y;
+#ifdef USE_LONG_LONG
+ unsigned long long carry;
#else
- ULong carry, *x, y;
-#ifdef Pack_32
- ULong xi, z;
+ uint32_t carry;
#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;
+ int wds = b->wds;
+ uint32_t* x = b->x;
+ int i = 0;
+ carry = a;
+ do {
+#ifdef USE_LONG_LONG
+ unsigned long long y = *x * (unsigned long long)m + carry;
+ carry = y >> 32;
+ *x++ = (uint32_t)y & 0xffffffffUL;
#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
+ uint32_t xi = *x;
+ uint32_t y = (xi & 0xffff) * m + carry;
+ uint32_t z = (xi >> 16) * m + (y >> 16);
+ carry = z >> 16;
+ *x++ = (z << 16) + (y & 0xffff);
+#else
+ uint32_t y = *x * m + carry;
+ carry = y >> 16;
+ *x++ = y & 0xffff;
+#endif
+#endif
+ } while (++i < wds);
+
+ if (carry) {
+ if (wds >= b->maxwds) {
+ Bigint* b1 = Balloc(b->k + 1);
+ Bcopy(b1, b);
+ Bfree(b);
+ b = b1;
+ }
+ b->x[wds++] = (uint32_t)carry;
+ b->wds = wds;
+ }
+ return b;
+}
+
+static Bigint* s2b(const char* s, int nd0, int nd, uint32_t y9)
{
- Bigint *b;
- int i, k;
- Long x, y;
+ int k;
+ int32_t y;
+ int32_t x = (nd + 8) / 9;
- x = (nd + 8) / 9;
- for(k = 0, y = 1; x > y; y <<= 1, k++) ;
+ 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
+ Bigint* b = Balloc(k);
+ b->x[0] = y9;
+ b->wds = 1;
+#else
+ Bigint* b = Balloc(k + 1);
+ b->x[0] = y9 & 0xffff;
+ b->wds = (b->x[1] = y9 >> 16) ? 2 : 1;
+#endif
+
+ int 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(uint32_t x)
{
- 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
+ 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 (uint32_t* y)
{
- 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
+ int k;
+ uint32_t 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(int i)
{
- 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* b;
+
+ b = Balloc(1);
+ b->x[0] = i;
+ b->wds = 1;
+ return b;
+}
+
+static Bigint* mult(Bigint* a, Bigint* b)
{
- 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;
- }
- }
+ Bigint* c;
+ int k, wa, wb, wc;
+ uint32_t *x, *xa, *xae, *xb, *xbe, *xc, *xc0;
+ uint32_t y;
+#ifdef USE_LONG_LONG
+ unsigned long long carry, z;
+#else
+ uint32_t carry, z;
+#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 USE_LONG_LONG
+ for (; xb < xbe; xc0++) {
+ if ((y = *xb++)) {
+ x = xa;
+ xc = xc0;
+ carry = 0;
+ do {
+ z = *x++ * (unsigned long long)y + *xc + carry;
+ carry = z >> 32;
+ *xc++ = (uint32_t)z & 0xffffffffUL;
+ } while (x < xae);
+ *xc = (uint32_t)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
+ 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;
+ uint32_t 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;
+ uint32_t 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 int p5s_count;
+
+static Bigint* pow5mult(Bigint* b, int k)
{
- 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
+ static int p05[3] = { 5, 25, 125 };
+
+ if (int i = k & 3)
+ b = multadd(b, p05[i - 1], 0);
+
+ if (!(k >>= 2))
+ return b;
+
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ s_dtoaP5Mutex->lock();
+#endif
+ Bigint* p5 = p5s;
+ if (!p5) {
+ /* first time */
+ p5 = p5s = i2b(625);
+ p5s_count = 1;
+ }
+ int p5s_count_local = p5s_count;
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ s_dtoaP5Mutex->unlock();
+#endif
+ int p5s_used = 0;
+
+ for (;;) {
+ if (k & 1) {
+ Bigint* b1 = mult(b, p5);
+ Bfree(b);
+ b = b1;
+ }
+ if (!(k >>= 1))
+ break;
+
+ if (++p5s_used == p5s_count_local) {
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ s_dtoaP5Mutex->lock();
+#endif
+ if (p5s_used == p5s_count) {
+ ASSERT(!p5->next);
+ p5->next = mult(p5, p5);
+ ++p5s_count;
+ }
+
+ p5s_count_local = p5s_count;
+#if ENABLE(JSC_MULTIPLE_THREADS)
+ s_dtoaP5Mutex->unlock();
+#endif
+ }
+ p5 = p5->next;
+ }
+
+ return b;
+}
+
+static Bigint* lshift(Bigint* b, int k)
{
- int i, k1, n, n1;
- Bigint *b1;
- ULong *x, *x1, *xe, z;
+ Bigint* result = b;
#ifdef Pack_32
- n = k >> 5;
+ int 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)
+ int n = k >> 4;
#endif
+
+ int k1 = b->k;
+ int n1 = n + b->wds + 1;
+ for (int i = b->maxwds; n1 > i; i <<= 1)
+ k1++;
+ if (b->k < k1)
+ result = Balloc(k1);
+
+ const uint32_t* srcStart = b->x;
+ uint32_t* dstStart = result->x;
+ const uint32_t* src = srcStart + b->wds - 1;
+ uint32_t* dst = dstStart + n1 - 1;
+#ifdef Pack_32
+ if (k &= 0x1f) {
+ uint32_t hiSubword = 0;
+ int s = 32 - k;
+ for (; src >= srcStart; --src) {
+ *dst-- = hiSubword | *src >> s;
+ hiSubword = *src << k;
+ }
+ *dst = hiSubword;
+ ASSERT(dst == dstStart + n);
+ result->wds = b->wds + n + (result->x[n1 - 1] != 0);
+ }
+#else
+ if (k &= 0xf) {
+ uint32_t hiSubword = 0;
+ int s = 16 - k;
+ for (; src >= srcStart; --src) {
+ *dst-- = hiSubword | *src >> s;
+ hiSubword = (*src << k) & 0xffff;
+ }
+ *dst = hiSubword;
+ ASSERT(dst == dstStart + n);
+ result->wds = b->wds + n + (result->x[n1 - 1] != 0);
+ }
+ #endif
+ else {
+ do {
+ *--dst = *src--;
+ } while (src >= srcStart);
+ result->wds = b->wds + n;
+ }
+ for (dst = dstStart + n; dst != dstStart; )
+ *--dst = 0;
+
+ if (result != b)
+ Bfree(b);
+ return result;
+}
+
+static int cmp(Bigint* a, Bigint* b)
{
- 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
+ uint32_t *xa, *xa0, *xb, *xb0;
+ int i, j;
+
+ i = a->wds;
+ j = b->wds;
+ ASSERT(i <= 1 || a->x[i - 1]);
+ ASSERT(j <= 1 || b->x[j - 1]);
+ 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(Bigint* a, Bigint* b)
{
- 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
+ Bigint* c;
+ int i, wa, wb;
+ uint32_t *xa, *xae, *xb, *xbe, *xc;
+
+ 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;
+#ifdef USE_LONG_LONG
+ unsigned long long borrow = 0;
+ do {
+ unsigned long long y = (unsigned long long)*xa++ - *xb++ - borrow;
+ borrow = y >> 32 & (uint32_t)1;
+ *xc++ = (uint32_t)y & 0xffffffffUL;
+ } while (xb < xbe);
+ while (xa < xae) {
+ unsigned long long y = *xa++ - borrow;
+ borrow = y >> 32 & (uint32_t)1;
+ *xc++ = (uint32_t)y & 0xffffffffUL;
+ }
+#else
+ uint32_t borrow = 0;
#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
+ do {
+ uint32_t y = (*xa & 0xffff) - (*xb & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ uint32_t z = (*xa++ >> 16) - (*xb++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ } while (xb < xbe);
+ while (xa < xae) {
+ uint32_t y = (*xa & 0xffff) - borrow;
+ borrow = (y & 0x10000) >> 16;
+ uint32_t z = (*xa++ >> 16) - borrow;
+ borrow = (z & 0x10000) >> 16;
+ Storeinc(xc, z, y);
+ }
+#else
+ do {
+ uint32_t y = *xa++ - *xb++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ } while (xb < xbe);
+ while (xa < xae) {
+ uint32_t y = *xa++ - borrow;
+ borrow = (y & 0x10000) >> 16;
+ *xc++ = y & 0xffff;
+ }
+#endif
+#endif
+ while (!*--xc)
+ wa--;
+ c->wds = wa;
+ return c;
+}
+
+static double ulp(double x)
{
- register Long L;
- double a;
+ register int32_t L;
+ double a;
- L = (word0(x) & Exp_mask) - (P-1)*Exp_msk1;
+ L = (word0(x) & Exp_mask) - (P - 1) * Exp_msk1;
#ifndef Avoid_Underflow
#ifndef Sudden_Underflow
- if (L > 0) {
-#endif
+ if (L > 0) {
#endif
-#ifdef IBM
- L |= Exp_msk1 >> 4;
#endif
- word0(a) = L;
- word1(a) = 0;
+ 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
+ } 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(Bigint* a, int* e)
{
- ULong *xa, *xa0, w, y, z;
- int k;
- double d;
-#ifdef VAX
- ULong d0, d1;
-#else
+ uint32_t* xa;
+ uint32_t* xa0;
+ uint32_t w;
+ uint32_t y;
+ uint32_t z;
+ int k;
+ double d;
+
#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;
+ xa0 = a->x;
+ xa = xa0 + a->wds;
+ y = *--xa;
+ ASSERT(y);
+ 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
+ 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:
#undef d0
#undef d1
-#endif
- return dval(d);
- }
+ 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
+static Bigint* d2b(double d, int* e, int* bits)
{
- Bigint *b;
- int de, k;
- ULong *x, y, z;
+ Bigint* b;
+ int de, k;
+ uint32_t *x, y, z;
#ifndef Sudden_Underflow
- int i;
+ 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);
+ b = Balloc(1);
#else
- b = Balloc(2);
+ b = Balloc(2);
#endif
- x = b->x;
+ x = b->x;
- z = d0 & Frac_mask;
- d0 &= 0x7fffffff; /* clear sign bit, which we ignore */
+ 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
+ de = (int)(d0 >> Exp_shift);
#else
- if ((de = (int)(d0 >> Exp_shift)))
- z |= Exp_msk1;
+ 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;
+ if ((y = d1)) {
+ if ((k = lo0bits(&y))) {
+ x[0] = y | z << 32 - k;
+ z >>= k;
+ } else
+ x[0] = y;
#ifndef Sudden_Underflow
- i =
+ 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;
+ b->wds = (x[1] = z) ? 2 : 1;
+ } else {
+ 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;
+ 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 {
+ 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;
+ if (de) {
#endif
+ *e = de - Bias - (P - 1) + k;
+ *bits = P - k;
#ifndef Sudden_Underflow
- }
- else {
- *e = de - Bias - (P-1) + 1 + k;
+ } else {
+ *e = de - Bias - (P - 1) + 1 + k;
#ifdef Pack_32
- *bits = 32*i - hi0bits(x[i-1]);
+ *bits = (32 * i) - hi0bits(x[i - 1]);
#else
- *bits = (i+2)*16 - hi0bits(x[i]);
+ *bits = (i + 2) * 16 - hi0bits(x[i]);
#endif
- }
+ }
#endif
- return b;
- }
+ return b;
+}
#undef d0
#undef d1
- static double
-ratio
-#ifdef KR_headers
- (a, b) Bigint *a, *b;
-#else
- (Bigint *a, Bigint *b)
-#endif
+static double ratio(Bigint* a, Bigint* b)
{
- double da, db;
- int k, ka, kb;
+ double da, db;
+ int k, ka, kb;
- dval(da) = b2d(a, &ka);
- dval(db) = b2d(b, &kb);
+ dval(da) = b2d(a, &ka);
+ dval(db) = b2d(b, &kb);
#ifdef Pack_32
- k = ka - kb + 32*(a->wds - b->wds);
+ 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,
+ k = ka - kb + 16 * (a->wds - b->wds);
+#endif
+ if (k > 0)
+ word0(da) += k * Exp_msk1;
+ else {
+ k = -k;
+ word0(db) += k * Exp_msk1;
+ }
+ 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
+};
+
+static const double 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 */
+ 9007199254740992. * 9007199254740992.e-256
+ /* = 2^106 * 1e-53 */
#else
- 1e-256
+ 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
+#if defined(INFNAN_CHECK)
#ifndef NAN_WORD0
#define NAN_WORD0 0x7ff80000
@@ -1457,1110 +1014,853 @@ static CONST_ double tinytens[] = { 1e-16, 1e-32 };
#define NAN_WORD1 0
#endif
- static int
-match
-#ifdef KR_headers
- (sp, t) char **sp, *t;
-#else
- (CONST_ char **sp, CONST_ char *t)
-#endif
+static int match(const char** sp, const char* t)
{
- 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;
- }
+ 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
+static void hexnan(double* rvp, const char** sp)
{
- 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];
- }
- }
+ uint32_t 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
+double strtod(const char* s00, char** se)
{
#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;
+ 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;
+ int32_t L;
+ uint32_t 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) {
+ int inexact, oldinexact;
+#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;
+ /* 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);
+ if (*s == '(') /*)*/
+ hexnan(&rv, &s);
#endif
- goto ret;
- }
- }
+ 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) {
+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;
- }
- }
+ if (k > DBL_DIG)
+ oldinexact = get_inexact();
+#endif
+ dval(rv) = tens[k - 9] * dval(rv) + z;
+ }
+ bd0 = 0;
+ if (nd <= DBL_DIG && Flt_Rounds == 1) {
+ if (!e)
+ goto ret;
+ if (e > 0) {
+ if (e <= Ten_pmax) {
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+ goto ret;
+ }
+ i = DBL_DIG - nd;
+ if (e <= Ten_pmax + i) {
+ /* A fancier test would sometimes let us do
+ * this for larger i values.
+ */
+ e -= i;
+ dval(rv) *= tens[i];
+ /* rv = */ rounded_product(dval(rv), tens[e]);
+ 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
+ else if (e >= -Ten_pmax) {
+ /* rv = */ rounded_quotient(dval(rv), tens[-e]);
+ goto ret;
+ }
+#endif
+ }
+ e1 += nd - k;
+
#ifdef SET_INEXACT
- inexact = 1;
- if (k <= DBL_DIG)
- oldinexact = get_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:
+ scale = 0;
+#endif
+
+ /* 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*/
+ errno = ERANGE;
+#endif
+ /* Can't trust HUGE_VAL */
+ word0(rv) = Exp_mask;
+ word1(rv) = 0;
#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;
+ /* set overflow bit */
+ dval(rv0) = 1e300;
+ dval(rv0) *= dval(rv0);
+#endif
+ 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.;
+ 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;
+ errno = ERANGE;
#endif
- if (bd0)
- goto retfree;
- goto ret;
- }
+ 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
+ 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 Avoid_Underflow
- j = bbe - scale;
- i = j + bbbits - 1; /* logb(rv) */
- if (i < Emin) /* denormal */
- j += P - Emin;
- else
- j = P + 1 - bbbits;
+ 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
+ j = P + 1 - bbbits;
#else /*Sudden_Underflow*/
- j = bbe;
- i = j + bbbits - 1; /* logb(rv) */
- if (i < Emin) /* denormal */
- j += P - Emin;
- else
- j = P + 1 - bbbits;
+ 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:
+ bb2 += j;
+ bd2 += j;
#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;
- }
- }
+ 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);
+
+ 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 Avoid_Underflow
- if (scale && (y = word0(rv) & Exp_mask) <= 2*P*Exp_msk1)
- word0(adj) += (2*P+1)*Exp_msk1 - y;
+ || (word0(rv) & Exp_mask) <= (2 * P + 1) * Exp_msk1
#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
+ || (word0(rv) & Exp_mask) <= Exp_msk1
#endif
- ) {
+ ) {
#ifdef SET_INEXACT
- if (!delta->x[0] && delta->wds <= 1)
- inexact = 0;
+ if (!delta->x[0] && delta->wds <= 1)
+ inexact = 0;
#endif
- break;
- }
- if (!delta->x[0] && delta->wds <= 1) {
- /* exact result */
+ 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) == (
+ 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;
+ (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;
+ word1(rv) = 0;
#ifdef Avoid_Underflow
- dsign = 0;
-#endif
- break;
- }
- }
- else if (!(word0(rv) & Bndry_mask) && !word1(rv)) {
- drop_down:
- /* boundary case -- decrement exponent */
+ 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
+ L = word0(rv) & Exp_mask;
#ifdef Avoid_Underflow
- if (L <= (scale ? (2*P+1)*Exp_msk1 : Exp_msk1))
+ if (L <= (scale ? (2 * P + 1) * Exp_msk1 : Exp_msk1))
#else
- if (L <= Exp_msk1)
+ if (L <= Exp_msk1)
#endif /*Avoid_Underflow*/
-#endif /*IBM*/
- goto undfl;
- L -= Exp_msk1;
+ 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;
- }
- }
+ 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;
+ 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));
+ word0(rv) = L | Bndry_mask1;
+ word1(rv) = 0xffffffff;
+ break;
+ }
+ if (!(word1(rv) & LSB))
+ break;
+ if (dsign)
+ dval(rv) += ulp(dval(rv));
+ else {
+ dval(rv) -= ulp(dval(rv));
#ifndef Sudden_Underflow
- if (!dval(rv))
- goto undfl;
+ 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) {
+ dsign = 1 - dsign;
+#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;
+ 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;
+ 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 {
+ }
+ 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;
+ if (scale && y <= 2 * P * Exp_msk1) {
+ if (aadj <= 0x7fffffff) {
+ if ((z = (uint32_t)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;
- }
+ 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;
+ if ((word0(rv) & Exp_mask) <= P * Exp_msk1)
+ {
+ 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;
+ /* 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;
+ }
+ 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);
- }
+ if (!scale)
+#endif
+ if (y == z) {
+ /* Can we stop now? */
+ L = (int32_t)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();
+ 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);
+ 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;
+ /* 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
+ 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(Bigint* b, Bigint* S)
{
- int n;
- ULong *bx, *bxe, q, *sx, *sxe;
-#ifdef ULLong
- ULLong borrow, carry, y, ys;
+ int n;
+ uint32_t *bx, *bxe, q, *sx, *sxe;
+#ifdef USE_LONG_LONG
+ unsigned long long borrow, carry, y, ys;
#else
- ULong borrow, carry, y, ys;
+ uint32_t 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;
+ uint32_t si, z, zs;
+#endif
+#endif
+
+ n = S->wds;
+ ASSERT_WITH_MESSAGE(b->wds <= n, "oversize b in quorem");
+ 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 */
+ ASSERT_WITH_MESSAGE(q <= 9, "oversized quotient in quorem");
+ if (q) {
+ borrow = 0;
+ carry = 0;
+ do {
+#ifdef USE_LONG_LONG
+ ys = *sx++ * (unsigned long long)q + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & 0xffffffffUL) - borrow;
+ borrow = y >> 32 & (uint32_t)1;
+ *bx++ = (uint32_t)y & 0xffffffffUL;
#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;
+ 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 USE_LONG_LONG
+ ys = *sx++ + carry;
+ carry = ys >> 32;
+ y = *bx - (ys & 0xffffffffUL) - borrow;
+ borrow = y >> 32 & (uint32_t)1;
+ *bx++ = (uint32_t)y & 0xffffffffUL;
#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)
+ 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;
+}
+
+#if !ENABLE(JSC_MULTIPLE_THREADS)
+static char* dtoa_result;
#endif
+
+static char* rv_alloc(int i)
{
- char *rv, *t;
+ int k;
+
+ int j = sizeof(uint32_t);
+ for (k = 0;
+ sizeof(Bigint) - sizeof(uint32_t) - sizeof(int) + j <= (unsigned)i;
+ j <<= 1)
+ k++;
+ int* r = (int*)Balloc(k);
+ *r = k;
+ return
+#if !ENABLE(JSC_MULTIPLE_THREADS)
+ dtoa_result =
+#endif
+ (char*)(r + 1);
+}
- t = rv = rv_alloc(n);
- while((*t = *s++)) t++;
- if (rve)
- *rve = t;
- return rv;
- }
+static char* nrv_alloc(const char* s, char** rve, int n)
+{
+ char* rv = rv_alloc(n);
+ char* t = rv;
+
+ 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,
@@ -2568,21 +1868,16 @@ nrv_alloc(CONST_ char *s, char **rve, int n)
* when MULTIPLE_THREADS is not defined.
*/
- void
-#ifdef KR_headers
-freedtoa(s) char *s;
-#else
-freedtoa(char *s)
-#endif
+void freedtoa(char* s)
{
- 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;
+ Bigint* b = (Bigint*)((int*)s - 1);
+ b->maxwds = 1 << (b->k = *(int*)b);
+ Bfree(b);
+#if !ENABLE(JSC_MULTIPLE_THREADS)
+ if (s == dtoa_result)
+ dtoa_result = 0;
#endif
- }
+}
/* dtoa for IEEE arithmetic (dmg): convert double to ASCII string.
*
@@ -2590,714 +1885,554 @@ freedtoa(char *s)
* 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.
+ * 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 int32_t
+ * 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
+char* dtoa(double d, int ndigits, int* decpt, int* sign, char** rve)
{
- /* 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;
+ /*
+ 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.
+
+ */
+
+ 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;
+ int32_t 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;
+ int denorm;
+ uint32_t x;
#endif
+ Bigint *b, *b1, *delta, *mlo = NULL, *mhi, *S;
+ double d2, ds, eps;
+ char *s, *s0;
#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);
- }
+ int inexact, oldinexact;
+#endif
+
+#if !ENABLE(JSC_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 ((word0(d) & Exp_mask) == Exp_mask)
+ {
+ /* Infinity or NaN */
+ *decpt = 9999;
+ if (!word1(d) && !(word0(d) & 0xfffff))
+ return nrv_alloc("Infinity", rve, 8);
+ return nrv_alloc("NaN", rve, 3);
+ }
+ 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;
- }
+ try_quick = oldinexact = get_inexact();
+ inexact = 1;
#endif
- b = d2b(dval(d), &be, &bbits);
+ 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
+ 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;
+
+ /* 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;
#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;
+ 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;
+ }
#ifndef SET_INEXACT
#ifdef Check_FLT_ROUNDS
- try_quick = Rounding == 1;
+ try_quick = Rounding == 1;
#else
- try_quick = 1;
+ 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;
- }
+ leftright = 1;
+ ilim = ilim1 = -1;
+ i = 18;
+ ndigits = 0;
+ s = s0 = rv_alloc(i);
+
+ 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;
- }
- }
+ 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 = (int32_t)(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;
+ }
+#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 = (int32_t)(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)) {
+ /* 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 =
+ inexact = 0;
+#endif
+ break;
+ }
+ if (i == ilim) {
+ 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)
+ denorm ? be + (Bias + (P - 1) - 1 + 1) :
+#endif
+ 1 + P - bbits;
+ 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 (!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.
- */
+ && 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++;
+ 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 (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);
+ if (j1 == 0 && !(word1(d) & 1)) {
+ 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) {
+ else if (!b->x[0] && b->wds <= 1)
+ inexact = 0;
+#endif
+ *s++ = dig;
+ goto ret;
+ }
+ if (j < 0 || j == 0 && !(word1(d) & 1)) {
+ 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) {
+ inexact = 0;
+#endif
+ goto accept_dig;
+ }
+ 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) {
+ if (dig == '9') { /* possible if i == 1 */
+round_9_up:
+ *s++ = '9';
+ goto roundoff;
+ }
+ *s++ = dig + 1;
+ goto ret;
+ }
+ *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:
+ inexact = 0;
+#endif
+ goto ret;
+ }
+ if (i >= ilim)
+ break;
+ b = multadd(b, 10, 0);
+ }
+
+ /* Round off last digit */
+
+ 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 {
+ while (*--s == '0') { }
+ s++;
+ }
+ goto ret;
+no_digits:
+ k = -1 - ndigits;
+ goto ret;
+one_digit:
+ *s++ = '1';
+ k++;
+ goto ret;
+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
+ 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;
}
-#endif
+
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/dtoa.h b/JavaScriptCore/kjs/dtoa.h
index 79ff828..690ebc8 100644
--- a/JavaScriptCore/kjs/dtoa.h
+++ b/JavaScriptCore/kjs/dtoa.h
@@ -1,7 +1,5 @@
-// -*- c-basic-offset: 2 -*-
/*
- * This file is part of the KDE libraries
- * Copyright (C) 2003 Apple Computer, Inc.
+ * Copyright (C) 2003, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -20,12 +18,21 @@
*
*/
-#ifndef _KJS_DTOA_H_
-#define _KJS_DTOA_H_
+#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);
+namespace WTF {
+ class Mutex;
+}
-#endif /* _KJS_DTOA_H */
+namespace JSC {
+
+ extern WTF::Mutex* s_dtoaP5Mutex;
+
+ double strtod(const char* s00, char** se);
+ char* dtoa(double d, int ndigits, int* decpt, int* sign, char** rve);
+ void freedtoa(char* s);
+
+} // namespace JSC
+
+#endif /* KJS_dtoa_h */
diff --git a/JavaScriptCore/kjs/error_object.cpp b/JavaScriptCore/kjs/error_object.cpp
deleted file mode 100644
index 75ef0ba..0000000
--- a/JavaScriptCore/kjs/error_object.cpp
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 9734085..0000000
--- a/JavaScriptCore/kjs/error_object.h
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 4ba54fd..0000000
--- a/JavaScriptCore/kjs/function.cpp
+++ /dev/null
@@ -1,885 +0,0 @@
-// -*- 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, int attr)
-{
- if (propertyName == exec->propertyNames().arguments || propertyName == exec->propertyNames().length)
- return;
- InternalFunctionImp::put(exec, propertyName, value, attr);
-}
-
-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, int attr)
-{
- if (indexToNameMap.isMapped(propertyName)) {
- _activationObject->put(exec, indexToNameMap[propertyName], value, attr);
- } else {
- JSObject::put(exec, propertyName, value, attr);
- }
-}
-
-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, int attr)
-{
- // If any bits other than DontDelete are set, then we bypass the read-only check.
- bool checkReadOnly = !(attr & ~DontDelete);
- if (symbolTablePut(propertyName, value, checkReadOnly))
- 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, attr, checkReadOnly);
-}
-
-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
deleted file mode 100644
index a45221e..0000000
--- a/JavaScriptCore/kjs/function.h
+++ /dev/null
@@ -1,161 +0,0 @@
-// -*- 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* value, int attr = None);
- 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* value, int attr = None);
- 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
deleted file mode 100644
index 5af2970..0000000
--- a/JavaScriptCore/kjs/function_object.cpp
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- * 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
- Debugger* dbg = exec->dynamicGlobalObject()->debugger();
- if (dbg) {
- // send empty sourceURL to indicate constructed code
- bool cont = dbg->sourceParsed(exec, sourceId, UString(), body, lineNumber, errLine, errMsg);
- if (!cont) {
- dbg->imp()->abort();
- 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 | DontDelete | ReadOnly);
- fimp->putDirect(exec->propertyNames().prototype, prototype, Internal | 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
deleted file mode 100644
index cd0fe3e..0000000
--- a/JavaScriptCore/kjs/function_object.h
+++ /dev/null
@@ -1,61 +0,0 @@
-// -*- 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
index 658ae89..370798d 100644
--- a/JavaScriptCore/kjs/grammar.y
+++ b/JavaScriptCore/kjs/grammar.y
@@ -1,8 +1,10 @@
+%pure_parser
+
%{
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 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
@@ -25,20 +27,17 @@
#include <string.h>
#include <stdlib.h>
-#include "value.h"
-#include "object.h"
-#include "types.h"
+#include "JSValue.h"
+#include "JSObject.h"
#include "nodes.h"
#include "lexer.h"
-#include "internal.h"
+#include "JSString.h"
+#include "JSGlobalData.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
@@ -50,30 +49,38 @@
#define YYERROR_VERBOSE
#endif
-extern int kjsyylex();
-int kjsyyerror(const char *);
-static bool allowAutomaticSemicolon();
+int kjsyylex(void* lvalp, void* llocp, void* globalPtr);
+int kjsyyerror(const char*);
+static inline bool allowAutomaticSemicolon(JSC::Lexer&, int);
+
+#define GLOBAL_DATA static_cast<JSGlobalData*>(globalPtr)
+#define LEXER (GLOBAL_DATA->lexer)
-#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon()) YYABORT; } while (0)
+#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon(*LEXER, yychar)) YYABORT; } while (0)
+#define SET_EXCEPTION_LOCATION(node, start, divot, end) node->setExceptionSourceCode((divot), (divot) - (start), (end) - (divot))
#define DBG(l, s, e) (l)->setLoc((s).first_line, (e).last_line)
-using namespace KJS;
+using namespace JSC;
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);
-
+static ExpressionNode* makeAssignNode(void*, ExpressionNode* loc, Operator, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end);
+static ExpressionNode* makePrefixNode(void*, ExpressionNode* expr, Operator, int start, int divot, int end);
+static ExpressionNode* makePostfixNode(void*, ExpressionNode* expr, Operator, int start, int divot, int end);
+static PropertyNode* makeGetterOrSetterPropertyNode(void*, const Identifier &getOrSet, const Identifier& name, ParameterNode*, FunctionBodyNode*, const SourceCode&);
+static ExpressionNodeInfo makeFunctionCallNode(void*, ExpressionNodeInfo func, ArgumentsNodeInfo, int start, int divot, int end);
+static ExpressionNode* makeTypeOfNode(void*, ExpressionNode*);
+static ExpressionNode* makeDeleteNode(void*, ExpressionNode*, int start, int divot, int end);
+static ExpressionNode* makeNegateNode(void*, ExpressionNode*);
+static NumberNode* makeNumberNode(void*, double);
+static ExpressionNode* makeBitwiseNotNode(void*, ExpressionNode*);
+static ExpressionNode* makeMultNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments);
+static ExpressionNode* makeDivNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments);
+static ExpressionNode* makeAddNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments);
+static ExpressionNode* makeSubNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments);
+static ExpressionNode* makeLeftShiftNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments);
+static ExpressionNode* makeRightShiftNode(void*, ExpressionNode*, ExpressionNode*, bool rightHasAssignments);
+static StatementNode* makeVarStatementNode(void*, ExpressionNode*);
+static ExpressionNode* combineVarInitializers(void*, ExpressionNode* list, AssignResolveNode* init);
#if COMPILER(MSVC)
@@ -89,10 +96,23 @@ static ExpressionNode* combineVarInitializers(ExpressionNode* list, AssignResolv
#endif
-template <typename T> NodeInfo<T> createNodeInfo(T node, ParserRefCountedData<DeclarationStacks::VarStack>* varDecls,
- ParserRefCountedData<DeclarationStacks::FunctionStack>* funcDecls)
+#define YYPARSE_PARAM globalPtr
+#define YYLEX_PARAM globalPtr
+
+template <typename T> NodeDeclarationInfo<T> createNodeDeclarationInfo(T node, ParserRefCountedData<DeclarationStacks::VarStack>* varDecls,
+ ParserRefCountedData<DeclarationStacks::FunctionStack>* funcDecls,
+ CodeFeatures info,
+ int numConstants)
{
- NodeInfo<T> result = {node, varDecls, funcDecls};
+ ASSERT((info & ~AllFeatures) == 0);
+ NodeDeclarationInfo<T> result = {node, varDecls, funcDecls, info, numConstants};
+ return result;
+}
+
+template <typename T> NodeInfo<T> createNodeInfo(T node, CodeFeatures info, int numConstants)
+{
+ ASSERT((info & ~AllFeatures) == 0);
+ NodeInfo<T> result = {node, info, numConstants};
return result;
}
@@ -115,21 +135,21 @@ template <typename T> T mergeDeclarationLists(T decls1, T decls2)
return decls1;
}
-static void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs)
+static void appendToVarDeclarationList(void* globalPtr, ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs)
{
if (!varDecls)
- varDecls = new ParserRefCountedData<DeclarationStacks::VarStack>;
+ varDecls = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA);
varDecls->data.append(make_pair(ident, attrs));
}
-static inline void appendToVarDeclarationList(ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl)
+static inline void appendToVarDeclarationList(void* globalPtr, ParserRefCountedData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl)
{
unsigned attrs = DeclarationStacks::IsConstant;
if (decl->m_init)
attrs |= DeclarationStacks::HasInitializer;
- appendToVarDeclarationList(varDecls, decl->m_ident, attrs);
+ appendToVarDeclarationList(globalPtr, varDecls, decl->m_ident, attrs);
}
%}
@@ -137,18 +157,17 @@ static inline void appendToVarDeclarationList(ParserRefCountedData<DeclarationSt
%union {
int intValue;
double doubleValue;
- UString* string;
Identifier* ident;
// expression subtrees
- ExpressionNode* expressionNode;
- FuncDeclNode* funcDeclNode;
- PropertyNode* propertyNode;
- ArgumentsNode* argumentsNode;
- ConstDeclNode* constDeclNode;
+ ExpressionNodeInfo expressionNode;
+ FuncDeclNodeInfo funcDeclNode;
+ PropertyNodeInfo propertyNode;
+ ArgumentsNodeInfo argumentsNode;
+ ConstDeclNodeInfo constDeclNode;
CaseBlockNodeInfo caseBlockNode;
CaseClauseNodeInfo caseClauseNode;
- FuncExprNode* funcExprNode;
+ FuncExprNodeInfo funcExprNode;
// statement nodes
StatementNodeInfo statementNode;
@@ -156,13 +175,13 @@ static inline void appendToVarDeclarationList(ParserRefCountedData<DeclarationSt
ProgramNode* programNode;
SourceElementsInfo sourceElements;
- PropertyList propertyList;
- ArgumentList argumentList;
+ PropertyListInfo propertyList;
+ ArgumentListInfo argumentList;
VarDeclListInfo varDeclList;
ConstDeclListInfo constDeclList;
ClauseListInfo clauseList;
- ElementList elementList;
- ParameterList parameterList;
+ ElementListInfo elementList;
+ ParameterListInfo parameterList;
Operator op;
}
@@ -198,11 +217,12 @@ static inline void appendToVarDeclarationList(ParserRefCountedData<DeclarationSt
%token RSHIFTEQUAL URSHIFTEQUAL /* >>= and >>>= */
%token ANDEQUAL MODEQUAL /* &= and %= */
%token XOREQUAL OREQUAL /* ^= and |= */
+%token <intValue> OPENBRACE /* { (with char offset) */
+%token <intValue> CLOSEBRACE /* { (with char offset) */
/* terminal types */
%token <doubleValue> NUMBER
-%token <string> STRING
-%token <ident> IDENT
+%token <ident> IDENT STRING
/* automatically inserted semicolon */
%token AUTOPLUSPLUS AUTOMINUSMINUS
@@ -264,69 +284,90 @@ static inline void appendToVarDeclarationList(ParserRefCountedData<DeclarationSt
%%
Literal:
- NULLTOKEN { $$ = new NullNode; }
- | TRUETOKEN { $$ = new TrueNode; }
- | FALSETOKEN { $$ = new FalseNode; }
- | NUMBER { $$ = makeNumberNode($1); }
- | STRING { $$ = new StringNode($1); }
+ NULLTOKEN { $$ = createNodeInfo<ExpressionNode*>(new NullNode(GLOBAL_DATA), 0, 1); }
+ | TRUETOKEN { $$ = createNodeInfo<ExpressionNode*>(new BooleanNode(GLOBAL_DATA, true), 0, 1); }
+ | FALSETOKEN { $$ = createNodeInfo<ExpressionNode*>(new BooleanNode(GLOBAL_DATA, false), 0, 1); }
+ | NUMBER { $$ = createNodeInfo<ExpressionNode*>(makeNumberNode(GLOBAL_DATA, $1), 0, 1); }
+ | STRING { $$ = createNodeInfo<ExpressionNode*>(new StringNode(GLOBAL_DATA, *$1), 0, 1); }
| '/' /* regexp */ {
- Lexer& l = lexer();
+ Lexer& l = *LEXER;
if (!l.scanRegExp())
YYABORT;
- $$ = new RegExpNode(l.pattern(), l.flags());
+ RegExpNode* node = new RegExpNode(GLOBAL_DATA, l.pattern(), l.flags());
+ int size = l.pattern().size() + 2; // + 2 for the two /'s
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.first_column + size, @1.first_column + size);
+ $$ = createNodeInfo<ExpressionNode*>(node, 0, 0);
}
| DIVEQUAL /* regexp with /= */ {
- Lexer& l = lexer();
+ Lexer& l = *LEXER;
if (!l.scanRegExp())
YYABORT;
- $$ = new RegExpNode("=" + l.pattern(), l.flags());
+ RegExpNode* node = new RegExpNode(GLOBAL_DATA, "=" + l.pattern(), l.flags());
+ int size = l.pattern().size() + 2; // + 2 for the two /'s
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.first_column + size, @1.first_column + size);
+ $$ = createNodeInfo<ExpressionNode*>(node, 0, 0);
}
;
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; }
+ IDENT ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); }
+ | STRING ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); }
+ | NUMBER ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new PropertyNode(GLOBAL_DATA, Identifier(GLOBAL_DATA, UString::from($1)), $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); }
+ | IDENT IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, 0, $6, LEXER->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); DBG($6, @5, @7); if (!$$.m_node) YYABORT; }
+ | IDENT IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
+ {
+ $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(globalPtr, *$1, *$2, $4.m_node.head, $7, LEXER->sourceCode($6, $8, @6.first_line)), $4.m_features | ClosureFeature, 0);
+ if ($4.m_features & ArgumentsFeature)
+ $7->setUsesArguments();
+ DBG($7, @6, @8);
+ if (!$$.m_node)
+ YYABORT;
+ }
;
PropertyList:
- Property { $$.head = new PropertyListNode($1);
- $$.tail = $$.head; }
- | PropertyList ',' Property { $$.head = $1.head;
- $$.tail = new PropertyListNode($3, $1.tail); }
+ Property { $$.m_node.head = new PropertyListNode(GLOBAL_DATA, $1.m_node);
+ $$.m_node.tail = $$.m_node.head;
+ $$.m_features = $1.m_features;
+ $$.m_numConstants = $1.m_numConstants; }
+ | PropertyList ',' Property { $$.m_node.head = $1.m_node.head;
+ $$.m_node.tail = new PropertyListNode(GLOBAL_DATA, $3.m_node, $1.m_node.tail);
+ $$.m_features = $1.m_features | $3.m_features;
+ $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; }
;
PrimaryExpr:
PrimaryExprNoBrace
- | '{' '}' { $$ = new ObjectLiteralNode(); }
- | '{' PropertyList '}' { $$ = new ObjectLiteralNode($2.head); }
+ | OPENBRACE CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new ObjectLiteralNode(GLOBAL_DATA), 0, 0); }
+ | OPENBRACE PropertyList CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new ObjectLiteralNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); }
/* allow extra comma, see http://bugs.webkit.org/show_bug.cgi?id=5939 */
- | '{' PropertyList ',' '}' { $$ = new ObjectLiteralNode($2.head); }
+ | OPENBRACE PropertyList ',' CLOSEBRACE { $$ = createNodeInfo<ExpressionNode*>(new ObjectLiteralNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); }
;
PrimaryExprNoBrace:
- THISTOKEN { $$ = new ThisNode(); }
+ THISTOKEN { $$ = createNodeInfo<ExpressionNode*>(new ThisNode(GLOBAL_DATA), ThisFeature, 0); }
| Literal
| ArrayLiteral
- | IDENT { $$ = new ResolveNode(*$1); }
+ | IDENT { $$ = createNodeInfo<ExpressionNode*>(new ResolveNode(GLOBAL_DATA, *$1, @1.first_column), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); }
| '(' Expr ')' { $$ = $2; }
;
ArrayLiteral:
- '[' ElisionOpt ']' { $$ = new ArrayNode($2); }
- | '[' ElementList ']' { $$ = new ArrayNode($2.head); }
- | '[' ElementList ',' ElisionOpt ']' { $$ = new ArrayNode($4, $2.head); }
+ '[' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new ArrayNode(GLOBAL_DATA, $2), 0, $2 ? 1 : 0); }
+ | '[' ElementList ']' { $$ = createNodeInfo<ExpressionNode*>(new ArrayNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); }
+ | '[' ElementList ',' ElisionOpt ']' { $$ = createNodeInfo<ExpressionNode*>(new ArrayNode(GLOBAL_DATA, $4, $2.m_node.head), $2.m_features, $4 ? $2.m_numConstants + 1 : $2.m_numConstants); }
;
ElementList:
- ElisionOpt AssignmentExpr { $$.head = new ElementNode($1, $2);
- $$.tail = $$.head; }
+ ElisionOpt AssignmentExpr { $$.m_node.head = new ElementNode(GLOBAL_DATA, $1, $2.m_node);
+ $$.m_node.tail = $$.m_node.head;
+ $$.m_features = $2.m_features;
+ $$.m_numConstants = $2.m_numConstants; }
| ElementList ',' ElisionOpt AssignmentExpr
- { $$.head = $1.head;
- $$.tail = new ElementNode($1.tail, $3, $4); }
+ { $$.m_node.head = $1.m_node.head;
+ $$.m_node.tail = new ElementNode(GLOBAL_DATA, $1.m_node.tail, $3, $4.m_node);
+ $$.m_features = $1.m_features | $4.m_features;
+ $$.m_numConstants = $1.m_numConstants + $4.m_numConstants; }
;
ElisionOpt:
@@ -341,53 +382,92 @@ Elision:
MemberExpr:
PrimaryExpr
- | FunctionExpr { $$ = $1; }
- | MemberExpr '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
- | MemberExpr '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
- | NEW MemberExpr Arguments { $$ = new NewExprNode($2, $3); }
+ | FunctionExpr { $$ = createNodeInfo<ExpressionNode*>($1.m_node, $1.m_features, $1.m_numConstants); }
+ | MemberExpr '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants);
+ }
+ | MemberExpr '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants);
+ }
+ | NEW MemberExpr Arguments { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features | $3.m_features, $2.m_numConstants + $3.m_numConstants);
+ }
;
MemberExprNoBF:
PrimaryExprNoBrace
- | MemberExprNoBF '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
- | MemberExprNoBF '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
- | NEW MemberExpr Arguments { $$ = new NewExprNode($2, $3); }
+ | MemberExprNoBF '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants);
+ }
+ | MemberExprNoBF '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants);
+ }
+ | NEW MemberExpr Arguments { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features | $3.m_features, $2.m_numConstants + $3.m_numConstants);
+ }
;
NewExpr:
MemberExpr
- | NEW NewExpr { $$ = new NewExprNode($2); }
+ | NEW NewExpr { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants);
+ }
;
NewExprNoBF:
MemberExprNoBF
- | NEW NewExpr { $$ = new NewExprNode($2); }
+ | NEW NewExpr { NewExprNode* node = new NewExprNode(GLOBAL_DATA, $2.m_node);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants);
+ }
;
CallExpr:
- MemberExpr Arguments { $$ = makeFunctionCallNode($1, $2); }
- | CallExpr Arguments { $$ = makeFunctionCallNode($1, $2); }
- | CallExpr '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
- | CallExpr '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
+ MemberExpr Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
+ | CallExpr Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
+ | CallExpr '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants);
+ }
+ | CallExpr '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); }
;
CallExprNoBF:
- MemberExprNoBF Arguments { $$ = makeFunctionCallNode($1, $2); }
- | CallExprNoBF Arguments { $$ = makeFunctionCallNode($1, $2); }
- | CallExprNoBF '[' Expr ']' { $$ = new BracketAccessorNode($1, $3); }
- | CallExprNoBF '.' IDENT { $$ = new DotAccessorNode($1, *$3); }
+ MemberExprNoBF Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
+ | CallExprNoBF Arguments { $$ = makeFunctionCallNode(globalPtr, $1, $2, @1.first_column, @1.last_column, @2.last_column); }
+ | CallExprNoBF '[' Expr ']' { BracketAccessorNode* node = new BracketAccessorNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @4.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants);
+ }
+ | CallExprNoBF '.' IDENT { DotAccessorNode* node = new DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants);
+ }
;
Arguments:
- '(' ')' { $$ = new ArgumentsNode(); }
- | '(' ArgumentList ')' { $$ = new ArgumentsNode($2.head); }
+ '(' ')' { $$ = createNodeInfo<ArgumentsNode*>(new ArgumentsNode(GLOBAL_DATA), 0, 0); }
+ | '(' ArgumentList ')' { $$ = createNodeInfo<ArgumentsNode*>(new ArgumentsNode(GLOBAL_DATA, $2.m_node.head), $2.m_features, $2.m_numConstants); }
;
ArgumentList:
- AssignmentExpr { $$.head = new ArgumentListNode($1);
- $$.tail = $$.head; }
- | ArgumentList ',' AssignmentExpr { $$.head = $1.head;
- $$.tail = new ArgumentListNode($1.tail, $3); }
+ AssignmentExpr { $$.m_node.head = new ArgumentListNode(GLOBAL_DATA, $1.m_node);
+ $$.m_node.tail = $$.m_node.head;
+ $$.m_features = $1.m_features;
+ $$.m_numConstants = $1.m_numConstants; }
+ | ArgumentList ',' AssignmentExpr { $$.m_node.head = $1.m_node.head;
+ $$.m_node.tail = new ArgumentListNode(GLOBAL_DATA, $1.m_node.tail, $3.m_node);
+ $$.m_features = $1.m_features | $3.m_features;
+ $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; }
;
LeftHandSideExpr:
@@ -402,28 +482,28 @@ LeftHandSideExprNoBF:
PostfixExpr:
LeftHandSideExpr
- | LeftHandSideExpr PLUSPLUS { $$ = makePostfixNode($1, OpPlusPlus); }
- | LeftHandSideExpr MINUSMINUS { $$ = makePostfixNode($1, OpMinusMinus); }
+ | LeftHandSideExpr PLUSPLUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); }
+ | LeftHandSideExpr MINUSMINUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); }
;
PostfixExprNoBF:
LeftHandSideExprNoBF
- | LeftHandSideExprNoBF PLUSPLUS { $$ = makePostfixNode($1, OpPlusPlus); }
- | LeftHandSideExprNoBF MINUSMINUS { $$ = makePostfixNode($1, OpMinusMinus); }
+ | LeftHandSideExprNoBF PLUSPLUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpPlusPlus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); }
+ | LeftHandSideExprNoBF MINUSMINUS { $$ = createNodeInfo<ExpressionNode*>(makePostfixNode(GLOBAL_DATA, $1.m_node, OpMinusMinus, @1.first_column, @1.last_column, @2.last_column), $1.m_features | AssignFeature, $1.m_numConstants); }
;
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); }
+ DELETETOKEN UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeDeleteNode(GLOBAL_DATA, $2.m_node, @1.first_column, @2.last_column, @2.last_column), $2.m_features, $2.m_numConstants); }
+ | VOIDTOKEN UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new VoidNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants + 1); }
+ | TYPEOF UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeTypeOfNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
+ | PLUSPLUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); }
+ | AUTOPLUSPLUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpPlusPlus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); }
+ | MINUSMINUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); }
+ | AUTOMINUSMINUS UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makePrefixNode(GLOBAL_DATA, $2.m_node, OpMinusMinus, @1.first_column, @2.first_column + 1, @2.last_column), $2.m_features | AssignFeature, $2.m_numConstants); }
+ | '+' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new UnaryPlusNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
+ | '-' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeNegateNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
+ | '~' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeBitwiseNotNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
+ | '!' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalNotNode(GLOBAL_DATA, $2.m_node), $2.m_features, $2.m_numConstants); }
UnaryExpr:
PostfixExpr
@@ -437,228 +517,245 @@ UnaryExprNoBF:
MultiplicativeExpr:
UnaryExpr
- | MultiplicativeExpr '*' UnaryExpr { $$ = new MultNode($1, $3); }
- | MultiplicativeExpr '/' UnaryExpr { $$ = new DivNode($1, $3); }
- | MultiplicativeExpr '%' UnaryExpr { $$ = new ModNode($1, $3); }
+ | MultiplicativeExpr '*' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeMultNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | MultiplicativeExpr '/' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(makeDivNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | MultiplicativeExpr '%' UnaryExpr { $$ = createNodeInfo<ExpressionNode*>(new ModNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
MultiplicativeExprNoBF:
UnaryExprNoBF
| MultiplicativeExprNoBF '*' UnaryExpr
- { $$ = new MultNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(makeMultNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| MultiplicativeExprNoBF '/' UnaryExpr
- { $$ = new DivNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(makeDivNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| MultiplicativeExprNoBF '%' UnaryExpr
- { $$ = new ModNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new ModNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
AdditiveExpr:
MultiplicativeExpr
- | AdditiveExpr '+' MultiplicativeExpr { $$ = makeAddNode($1, $3); }
- | AdditiveExpr '-' MultiplicativeExpr { $$ = new SubNode($1, $3); }
+ | AdditiveExpr '+' MultiplicativeExpr { $$ = createNodeInfo<ExpressionNode*>(makeAddNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | AdditiveExpr '-' MultiplicativeExpr { $$ = createNodeInfo<ExpressionNode*>(makeSubNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
AdditiveExprNoBF:
MultiplicativeExprNoBF
| AdditiveExprNoBF '+' MultiplicativeExpr
- { $$ = makeAddNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(makeAddNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| AdditiveExprNoBF '-' MultiplicativeExpr
- { $$ = new SubNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(makeSubNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
ShiftExpr:
AdditiveExpr
- | ShiftExpr LSHIFT AdditiveExpr { $$ = new LeftShiftNode($1, $3); }
- | ShiftExpr RSHIFT AdditiveExpr { $$ = new RightShiftNode($1, $3); }
- | ShiftExpr URSHIFT AdditiveExpr { $$ = new UnsignedRightShiftNode($1, $3); }
+ | ShiftExpr LSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeLeftShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | ShiftExpr RSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | ShiftExpr URSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(new UnsignedRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
ShiftExprNoBF:
AdditiveExprNoBF
- | ShiftExprNoBF LSHIFT AdditiveExpr { $$ = new LeftShiftNode($1, $3); }
- | ShiftExprNoBF RSHIFT AdditiveExpr { $$ = new RightShiftNode($1, $3); }
- | ShiftExprNoBF URSHIFT AdditiveExpr { $$ = new UnsignedRightShiftNode($1, $3); }
+ | ShiftExprNoBF LSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeLeftShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | ShiftExprNoBF RSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(makeRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | ShiftExprNoBF URSHIFT AdditiveExpr { $$ = createNodeInfo<ExpressionNode*>(new UnsignedRightShiftNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
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); }
+ | RelationalExpr '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExpr '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExpr LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExpr GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExpr INSTANCEOF ShiftExpr { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExpr INTOKEN ShiftExpr { InNode* node = new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
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 '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExprNoIn '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExprNoIn LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExprNoIn GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| RelationalExprNoIn INSTANCEOF ShiftExpr
- { $$ = new InstanceOfNode($1, $3); }
+ { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
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 '<' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExprNoBF '>' ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExprNoBF LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new LessEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExprNoBF GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new GreaterEqNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| RelationalExprNoBF INSTANCEOF ShiftExpr
- { $$ = new InstanceOfNode($1, $3); }
- | RelationalExprNoBF INTOKEN ShiftExpr { $$ = new InNode($1, $3); }
+ { InstanceOfNode* node = new InstanceOfNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | RelationalExprNoBF INTOKEN ShiftExpr
+ { InNode* node = new InNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @3.first_column, @3.last_column);
+ $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
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); }
+ | EqualityExpr EQEQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | EqualityExpr NE RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | EqualityExpr STREQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | EqualityExpr STRNEQ RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
EqualityExprNoIn:
RelationalExprNoIn
| EqualityExprNoIn EQEQ RelationalExprNoIn
- { $$ = new EqualNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| EqualityExprNoIn NE RelationalExprNoIn
- { $$ = new NotEqualNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| EqualityExprNoIn STREQ RelationalExprNoIn
- { $$ = new StrictEqualNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| EqualityExprNoIn STRNEQ RelationalExprNoIn
- { $$ = new NotStrictEqualNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
EqualityExprNoBF:
RelationalExprNoBF
| EqualityExprNoBF EQEQ RelationalExpr
- { $$ = new EqualNode($1, $3); }
- | EqualityExprNoBF NE RelationalExpr { $$ = new NotEqualNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new EqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
+ | EqualityExprNoBF NE RelationalExpr { $$ = createNodeInfo<ExpressionNode*>(new NotEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| EqualityExprNoBF STREQ RelationalExpr
- { $$ = new StrictEqualNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new StrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
| EqualityExprNoBF STRNEQ RelationalExpr
- { $$ = new NotStrictEqualNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new NotStrictEqualNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
BitwiseANDExpr:
EqualityExpr
- | BitwiseANDExpr '&' EqualityExpr { $$ = new BitAndNode($1, $3); }
+ | BitwiseANDExpr '&' EqualityExpr { $$ = createNodeInfo<ExpressionNode*>(new BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
BitwiseANDExprNoIn:
EqualityExprNoIn
| BitwiseANDExprNoIn '&' EqualityExprNoIn
- { $$ = new BitAndNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
BitwiseANDExprNoBF:
EqualityExprNoBF
- | BitwiseANDExprNoBF '&' EqualityExpr { $$ = new BitAndNode($1, $3); }
+ | BitwiseANDExprNoBF '&' EqualityExpr { $$ = createNodeInfo<ExpressionNode*>(new BitAndNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
BitwiseXORExpr:
BitwiseANDExpr
- | BitwiseXORExpr '^' BitwiseANDExpr { $$ = new BitXOrNode($1, $3); }
+ | BitwiseXORExpr '^' BitwiseANDExpr { $$ = createNodeInfo<ExpressionNode*>(new BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
BitwiseXORExprNoIn:
BitwiseANDExprNoIn
| BitwiseXORExprNoIn '^' BitwiseANDExprNoIn
- { $$ = new BitXOrNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
BitwiseXORExprNoBF:
BitwiseANDExprNoBF
| BitwiseXORExprNoBF '^' BitwiseANDExpr
- { $$ = new BitXOrNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new BitXOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
BitwiseORExpr:
BitwiseXORExpr
- | BitwiseORExpr '|' BitwiseXORExpr { $$ = new BitOrNode($1, $3); }
+ | BitwiseORExpr '|' BitwiseXORExpr { $$ = createNodeInfo<ExpressionNode*>(new BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
BitwiseORExprNoIn:
BitwiseXORExprNoIn
| BitwiseORExprNoIn '|' BitwiseXORExprNoIn
- { $$ = new BitOrNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
BitwiseORExprNoBF:
BitwiseXORExprNoBF
| BitwiseORExprNoBF '|' BitwiseXORExpr
- { $$ = new BitOrNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new BitOrNode(GLOBAL_DATA, $1.m_node, $3.m_node, $3.m_features & AssignFeature), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
LogicalANDExpr:
BitwiseORExpr
- | LogicalANDExpr AND BitwiseORExpr { $$ = new LogicalAndNode($1, $3); }
+ | LogicalANDExpr AND BitwiseORExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
LogicalANDExprNoIn:
BitwiseORExprNoIn
| LogicalANDExprNoIn AND BitwiseORExprNoIn
- { $$ = new LogicalAndNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
LogicalANDExprNoBF:
BitwiseORExprNoBF
| LogicalANDExprNoBF AND BitwiseORExpr
- { $$ = new LogicalAndNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalAnd), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
LogicalORExpr:
LogicalANDExpr
- | LogicalORExpr OR LogicalANDExpr { $$ = new LogicalOrNode($1, $3); }
+ | LogicalORExpr OR LogicalANDExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
LogicalORExprNoIn:
LogicalANDExprNoIn
| LogicalORExprNoIn OR LogicalANDExprNoIn
- { $$ = new LogicalOrNode($1, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
LogicalORExprNoBF:
LogicalANDExprNoBF
- | LogicalORExprNoBF OR LogicalANDExpr { $$ = new LogicalOrNode($1, $3); }
+ | LogicalORExprNoBF OR LogicalANDExpr { $$ = createNodeInfo<ExpressionNode*>(new LogicalOpNode(GLOBAL_DATA, $1.m_node, $3.m_node, OpLogicalOr), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
ConditionalExpr:
LogicalORExpr
| LogicalORExpr '?' AssignmentExpr ':' AssignmentExpr
- { $$ = new ConditionalNode($1, $3, $5); }
+ { $$ = createNodeInfo<ExpressionNode*>(new ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); }
;
ConditionalExprNoIn:
LogicalORExprNoIn
| LogicalORExprNoIn '?' AssignmentExprNoIn ':' AssignmentExprNoIn
- { $$ = new ConditionalNode($1, $3, $5); }
+ { $$ = createNodeInfo<ExpressionNode*>(new ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); }
;
ConditionalExprNoBF:
LogicalORExprNoBF
| LogicalORExprNoBF '?' AssignmentExpr ':' AssignmentExpr
- { $$ = new ConditionalNode($1, $3, $5); }
+ { $$ = createNodeInfo<ExpressionNode*>(new ConditionalNode(GLOBAL_DATA, $1.m_node, $3.m_node, $5.m_node), $1.m_features | $3.m_features | $5.m_features, $1.m_numConstants + $3.m_numConstants + $5.m_numConstants); }
;
AssignmentExpr:
ConditionalExpr
| LeftHandSideExpr AssignmentOperator AssignmentExpr
- { $$ = makeAssignNode($1, $2, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature,
+ @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants);
+ }
;
AssignmentExprNoIn:
ConditionalExprNoIn
| LeftHandSideExpr AssignmentOperator AssignmentExprNoIn
- { $$ = makeAssignNode($1, $2, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature,
+ @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants);
+ }
;
AssignmentExprNoBF:
ConditionalExprNoBF
| LeftHandSideExprNoBF AssignmentOperator AssignmentExpr
- { $$ = makeAssignNode($1, $2, $3); }
+ { $$ = createNodeInfo<ExpressionNode*>(makeAssignNode(GLOBAL_DATA, $1.m_node, $2, $3.m_node, $1.m_features & AssignFeature, $3.m_features & AssignFeature,
+ @1.first_column, @2.first_column + 1, @3.last_column), $1.m_features | $3.m_features | AssignFeature, $1.m_numConstants + $3.m_numConstants);
+ }
;
AssignmentOperator:
@@ -678,17 +775,17 @@ AssignmentOperator:
Expr:
AssignmentExpr
- | Expr ',' AssignmentExpr { $$ = new CommaNode($1, $3); }
+ | Expr ',' AssignmentExpr { $$ = createNodeInfo<ExpressionNode*>(new CommaNode(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
ExprNoIn:
AssignmentExprNoIn
- | ExprNoIn ',' AssignmentExprNoIn { $$ = new CommaNode($1, $3); }
+ | ExprNoIn ',' AssignmentExprNoIn { $$ = createNodeInfo<ExpressionNode*>(new CommaNode(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
ExprNoBF:
AssignmentExprNoBF
- | ExprNoBF ',' AssignmentExpr { $$ = new CommaNode($1, $3); }
+ | ExprNoBF ',' AssignmentExpr { $$ = createNodeInfo<ExpressionNode*>(new CommaNode(GLOBAL_DATA, $1.m_node, $3.m_node), $1.m_features | $3.m_features, $1.m_numConstants + $3.m_numConstants); }
;
Statement:
@@ -711,96 +808,125 @@ Statement:
;
Block:
- '{' '}' { $$ = createNodeInfo<StatementNode*>(new BlockNode(0), 0, 0);
+ OPENBRACE CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new BlockNode(GLOBAL_DATA, 0), 0, 0, 0, 0);
DBG($$.m_node, @1, @2); }
- | '{' SourceElements '}' { $$ = createNodeInfo<StatementNode*>(new BlockNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
+ | OPENBRACE SourceElements CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new BlockNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
DBG($$.m_node, @1, @3); }
;
VariableStatement:
- VAR VariableDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(makeVarStatementNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
+ VAR VariableDeclarationList ';' { $$ = createNodeDeclarationInfo<StatementNode*>(makeVarStatementNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
DBG($$.m_node, @1, @3); }
- | VAR VariableDeclarationList error { $$ = createNodeInfo<StatementNode*>(makeVarStatementNode($2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations);
+ | VAR VariableDeclarationList error { $$ = createNodeDeclarationInfo<StatementNode*>(makeVarStatementNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
DBG($$.m_node, @1, @2);
AUTO_SEMICOLON; }
;
VariableDeclarationList:
IDENT { $$.m_node = 0;
- $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList($$.m_varDeclarations, *$1, 0);
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA);
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, 0);
$$.m_funcDeclarations = 0;
+ $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0;
+ $$.m_numConstants = 0;
}
- | IDENT Initializer { $$.m_node = new AssignResolveNode(*$1, $2);
- $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList($$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
+ | IDENT Initializer { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.first_column + 1, @2.last_column);
+ $$.m_node = node;
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA);
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
$$.m_funcDeclarations = 0;
+ $$.m_features = ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features;
+ $$.m_numConstants = $2.m_numConstants;
}
| VariableDeclarationList ',' IDENT
{ $$.m_node = $1.m_node;
$$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList($$.m_varDeclarations, *$3, 0);
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, 0);
$$.m_funcDeclarations = 0;
+ $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0);
+ $$.m_numConstants = $1.m_numConstants;
}
| VariableDeclarationList ',' IDENT Initializer
- { $$.m_node = combineVarInitializers($1.m_node, new AssignResolveNode(*$3, $4));
+ { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @3.first_column, @4.first_column + 1, @4.last_column);
+ $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, node);
$$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList($$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
$$.m_funcDeclarations = 0;
+ $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features;
+ $$.m_numConstants = $1.m_numConstants + $4.m_numConstants;
}
;
VariableDeclarationListNoIn:
IDENT { $$.m_node = 0;
- $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList($$.m_varDeclarations, *$1, 0);
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA);
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, 0);
$$.m_funcDeclarations = 0;
+ $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0;
+ $$.m_numConstants = 0;
}
- | IDENT InitializerNoIn { $$.m_node = new AssignResolveNode(*$1, $2);
- $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList($$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
+ | IDENT InitializerNoIn { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$1, $2.m_node, $2.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.first_column + 1, @2.last_column);
+ $$.m_node = node;
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA);
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer);
$$.m_funcDeclarations = 0;
+ $$.m_features = ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features;
+ $$.m_numConstants = $2.m_numConstants;
}
| VariableDeclarationListNoIn ',' IDENT
{ $$.m_node = $1.m_node;
$$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList($$.m_varDeclarations, *$3, 0);
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, 0);
$$.m_funcDeclarations = 0;
+ $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0);
+ $$.m_numConstants = $1.m_numConstants;
}
| VariableDeclarationListNoIn ',' IDENT InitializerNoIn
- { $$.m_node = combineVarInitializers($1.m_node, new AssignResolveNode(*$3, $4));
+ { AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, *$3, $4.m_node, $4.m_features & AssignFeature);
+ SET_EXCEPTION_LOCATION(node, @3.first_column, @4.first_column + 1, @4.last_column);
+ $$.m_node = combineVarInitializers(GLOBAL_DATA, $1.m_node, node);
$$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList($$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer);
$$.m_funcDeclarations = 0;
+ $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features;
+ $$.m_numConstants = $1.m_numConstants + $4.m_numConstants;
}
;
ConstStatement:
- CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeInfo<StatementNode*>(new ConstStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+ CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new ConstStatementNode(GLOBAL_DATA, $2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
DBG($$.m_node, @1, @3); }
| CONSTTOKEN ConstDeclarationList error
- { $$ = createNodeInfo<StatementNode*>(new ConstStatementNode($2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations);
+ { $$ = createNodeDeclarationInfo<StatementNode*>(new ConstStatementNode(GLOBAL_DATA, $2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants);
DBG($$.m_node, @1, @2); AUTO_SEMICOLON; }
;
ConstDeclarationList:
- ConstDeclaration { $$.m_node.head = $1;
+ ConstDeclaration { $$.m_node.head = $1.m_node;
$$.m_node.tail = $$.m_node.head;
- $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>;
- appendToVarDeclarationList($$.m_varDeclarations, $1);
- $$.m_funcDeclarations = 0; }
+ $$.m_varDeclarations = new ParserRefCountedData<DeclarationStacks::VarStack>(GLOBAL_DATA);
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, $1.m_node);
+ $$.m_funcDeclarations = 0;
+ $$.m_features = $1.m_features;
+ $$.m_numConstants = $1.m_numConstants;
+ }
| ConstDeclarationList ',' ConstDeclaration
{ $$.m_node.head = $1.m_node.head;
- $1.m_node.tail->m_next = $3;
- $$.m_node.tail = $3;
+ $1.m_node.tail->m_next = $3.m_node;
+ $$.m_node.tail = $3.m_node;
$$.m_varDeclarations = $1.m_varDeclarations;
- appendToVarDeclarationList($$.m_varDeclarations, $3);
- $$.m_funcDeclarations = 0; }
+ appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, $3.m_node);
+ $$.m_funcDeclarations = 0;
+ $$.m_features = $1.m_features | $3.m_features;
+ $$.m_numConstants = $1.m_numConstants + $3.m_numConstants; }
;
ConstDeclaration:
- IDENT { $$ = new ConstDeclNode(*$1, 0); }
- | IDENT Initializer { $$ = new ConstDeclNode(*$1, $2); }
+ IDENT { $$ = createNodeInfo<ConstDeclNode*>(new ConstDeclNode(GLOBAL_DATA, *$1, 0), (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0, 0); }
+ | IDENT Initializer { $$ = createNodeInfo<ConstDeclNode*>(new ConstDeclNode(GLOBAL_DATA, *$1, $2.m_node), ((*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $2.m_features, $2.m_numConstants); }
;
Initializer:
@@ -812,198 +938,275 @@ InitializerNoIn:
;
EmptyStatement:
- ';' { $$ = createNodeInfo<StatementNode*>(new EmptyStatementNode(), 0, 0); }
+ ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new EmptyStatementNode(GLOBAL_DATA), 0, 0, 0, 0); }
;
ExprStatement:
- ExprNoBF ';' { $$ = createNodeInfo<StatementNode*>(new ExprStatementNode($1), 0, 0);
+ ExprNoBF ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants);
DBG($$.m_node, @1, @2); }
- | ExprNoBF error { $$ = createNodeInfo<StatementNode*>(new ExprStatementNode($1), 0, 0);
+ | ExprNoBF error { $$ = createNodeDeclarationInfo<StatementNode*>(new ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants);
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);
+ { $$ = createNodeDeclarationInfo<StatementNode*>(new IfNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants);
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));
+ { $$ = createNodeDeclarationInfo<StatementNode*>(new IfElseNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node),
+ mergeDeclarationLists($5.m_varDeclarations, $7.m_varDeclarations), mergeDeclarationLists($5.m_funcDeclarations, $7.m_funcDeclarations),
+ $3.m_features | $5.m_features | $7.m_features,
+ $3.m_numConstants + $5.m_numConstants + $7.m_numConstants);
DBG($$.m_node, @1, @4); }
;
IterationStatement:
- DO Statement WHILE '(' Expr ')' ';' { $$ = createNodeInfo<StatementNode*>(new DoWhileNode($2.m_node, $5), $2.m_varDeclarations, $2.m_funcDeclarations);
+ DO Statement WHILE '(' Expr ')' ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new DoWhileNode(GLOBAL_DATA, $2.m_node, $5.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features | $5.m_features, $2.m_numConstants + $5.m_numConstants);
DBG($$.m_node, @1, @3); }
- | DO Statement WHILE '(' Expr ')' error { $$ = createNodeInfo<StatementNode*>(new DoWhileNode($2.m_node, $5), $2.m_varDeclarations, $2.m_funcDeclarations);
+ | DO Statement WHILE '(' Expr ')' error { $$ = createNodeDeclarationInfo<StatementNode*>(new DoWhileNode(GLOBAL_DATA, $2.m_node, $5.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features | $5.m_features, $2.m_numConstants + $5.m_numConstants);
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);
+ | WHILE '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new WhileNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants);
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);
+ { $$ = createNodeDeclarationInfo<StatementNode*>(new ForNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node, $9.m_node, false), $9.m_varDeclarations, $9.m_funcDeclarations,
+ $3.m_features | $5.m_features | $7.m_features | $9.m_features,
+ $3.m_numConstants + $5.m_numConstants + $7.m_numConstants + $9.m_numConstants);
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));
+ { $$ = createNodeDeclarationInfo<StatementNode*>(new ForNode(GLOBAL_DATA, $4.m_node, $6.m_node, $8.m_node, $10.m_node, true),
+ mergeDeclarationLists($4.m_varDeclarations, $10.m_varDeclarations),
+ mergeDeclarationLists($4.m_funcDeclarations, $10.m_funcDeclarations),
+ $4.m_features | $6.m_features | $8.m_features | $10.m_features,
+ $4.m_numConstants + $6.m_numConstants + $8.m_numConstants + $10.m_numConstants);
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);
+ ForInNode* node = new ForInNode(GLOBAL_DATA, $3.m_node, $5.m_node, $7.m_node);
+ SET_EXCEPTION_LOCATION(node, @3.first_column, @3.last_column, @5.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, $7.m_varDeclarations, $7.m_funcDeclarations,
+ $3.m_features | $5.m_features | $7.m_features,
+ $3.m_numConstants + $5.m_numConstants + $7.m_numConstants);
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);
+ { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, 0, $6.m_node, $8.m_node, @5.first_column, @5.first_column - @4.first_column, @6.last_column - @5.first_column);
+ SET_EXCEPTION_LOCATION(forIn, @4.first_column, @5.first_column + 1, @6.last_column);
+ appendToVarDeclarationList(GLOBAL_DATA, $8.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
+ $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $8.m_varDeclarations, $8.m_funcDeclarations, ((*$4 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $6.m_features | $8.m_features, $6.m_numConstants + $8.m_numConstants);
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);
+ { ForInNode *forIn = new ForInNode(GLOBAL_DATA, *$4, $5.m_node, $7.m_node, $9.m_node, @5.first_column, @5.first_column - @4.first_column, @5.last_column - @5.first_column);
+ SET_EXCEPTION_LOCATION(forIn, @4.first_column, @6.first_column + 1, @7.last_column);
+ appendToVarDeclarationList(GLOBAL_DATA, $9.m_varDeclarations, *$4, DeclarationStacks::HasInitializer);
+ $$ = createNodeDeclarationInfo<StatementNode*>(forIn, $9.m_varDeclarations, $9.m_funcDeclarations,
+ ((*$4 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $5.m_features | $7.m_features | $9.m_features,
+ $5.m_numConstants + $7.m_numConstants + $9.m_numConstants);
DBG($$.m_node, @1, @8); }
;
ExprOpt:
- /* nothing */ { $$ = 0; }
+ /* nothing */ { $$ = createNodeInfo<ExpressionNode*>(0, 0, 0); }
| Expr
;
ExprNoInOpt:
- /* nothing */ { $$ = 0; }
+ /* nothing */ { $$ = createNodeInfo<ExpressionNode*>(0, 0, 0); }
| ExprNoIn
;
ContinueStatement:
- CONTINUE ';' { $$ = createNodeInfo<StatementNode*>(new ContinueNode(), 0, 0);
+ CONTINUE ';' { ContinueNode* node = new ContinueNode(GLOBAL_DATA);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0);
DBG($$.m_node, @1, @2); }
- | CONTINUE error { $$ = createNodeInfo<StatementNode*>(new ContinueNode(), 0, 0);
+ | CONTINUE error { ContinueNode* node = new ContinueNode(GLOBAL_DATA);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0);
DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
- | CONTINUE IDENT ';' { $$ = createNodeInfo<StatementNode*>(new ContinueNode(*$2), 0, 0);
+ | CONTINUE IDENT ';' { ContinueNode* node = new ContinueNode(GLOBAL_DATA, *$2);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0);
DBG($$.m_node, @1, @3); }
- | CONTINUE IDENT error { $$ = createNodeInfo<StatementNode*>(new ContinueNode(*$2), 0, 0);
+ | CONTINUE IDENT error { ContinueNode* node = new ContinueNode(GLOBAL_DATA, *$2);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 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; }
+ BREAK ';' { BreakNode* node = new BreakNode(GLOBAL_DATA);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @2); }
+ | BREAK error { BreakNode* node = new BreakNode(GLOBAL_DATA);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA), 0, 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+ | BREAK IDENT ';' { BreakNode* node = new BreakNode(GLOBAL_DATA, *$2);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @3); }
+ | BREAK IDENT error { BreakNode* node = new BreakNode(GLOBAL_DATA, *$2);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(new BreakNode(GLOBAL_DATA, *$2), 0, 0, 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; }
+ RETURN ';' { ReturnNode* node = new ReturnNode(GLOBAL_DATA, 0);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @2); }
+ | RETURN error { ReturnNode* node = new ReturnNode(GLOBAL_DATA, 0);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; }
+ | RETURN Expr ';' { ReturnNode* node = new ReturnNode(GLOBAL_DATA, $2.m_node);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @3); }
+ | RETURN Expr error { ReturnNode* node = new ReturnNode(GLOBAL_DATA, $2.m_node);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); 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);
+ WITH '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new WithNode(GLOBAL_DATA, $3.m_node, $5.m_node, @3.last_column, @3.last_column - @3.first_column),
+ $5.m_varDeclarations, $5.m_funcDeclarations, $3.m_features | $5.m_features | WithFeature, $3.m_numConstants + $5.m_numConstants);
DBG($$.m_node, @1, @4); }
;
SwitchStatement:
- SWITCH '(' Expr ')' CaseBlock { $$ = createNodeInfo<StatementNode*>(new SwitchNode($3, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations);
+ SWITCH '(' Expr ')' CaseBlock { $$ = createNodeDeclarationInfo<StatementNode*>(new SwitchNode(GLOBAL_DATA, $3.m_node, $5.m_node), $5.m_varDeclarations, $5.m_funcDeclarations,
+ $3.m_features | $5.m_features, $3.m_numConstants + $5.m_numConstants);
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)); }
+ OPENBRACE CaseClausesOpt CLOSEBRACE { $$ = createNodeDeclarationInfo<CaseBlockNode*>(new CaseBlockNode(GLOBAL_DATA, $2.m_node.head, 0, 0), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); }
+ | OPENBRACE CaseClausesOpt DefaultClause CaseClausesOpt CLOSEBRACE
+ { $$ = createNodeDeclarationInfo<CaseBlockNode*>(new CaseBlockNode(GLOBAL_DATA, $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),
+ $2.m_features | $3.m_features | $4.m_features,
+ $2.m_numConstants + $3.m_numConstants + $4.m_numConstants); }
;
CaseClausesOpt:
- /* nothing */ { $$.m_node.head = 0; $$.m_node.tail = 0; $$.m_varDeclarations = 0; $$.m_funcDeclarations = 0; }
+/* nothing */ { $$.m_node.head = 0; $$.m_node.tail = 0; $$.m_varDeclarations = 0; $$.m_funcDeclarations = 0; $$.m_features = 0; $$.m_numConstants = 0; }
| CaseClauses
;
CaseClauses:
- CaseClause { $$.m_node.head = new ClauseListNode($1.m_node);
+ CaseClause { $$.m_node.head = new ClauseListNode(GLOBAL_DATA, $1.m_node);
$$.m_node.tail = $$.m_node.head;
$$.m_varDeclarations = $1.m_varDeclarations;
- $$.m_funcDeclarations = $1.m_funcDeclarations; }
+ $$.m_funcDeclarations = $1.m_funcDeclarations;
+ $$.m_features = $1.m_features;
+ $$.m_numConstants = $1.m_numConstants; }
| CaseClauses CaseClause { $$.m_node.head = $1.m_node.head;
- $$.m_node.tail = new ClauseListNode($1.m_node.tail, $2.m_node);
+ $$.m_node.tail = new ClauseListNode(GLOBAL_DATA, $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);
+ $$.m_features = $1.m_features | $2.m_features;
+ $$.m_numConstants = $1.m_numConstants + $2.m_numConstants;
}
;
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); }
+ CASE Expr ':' { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, $2.m_node), 0, 0, $2.m_features, $2.m_numConstants); }
+ | CASE Expr ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, $2.m_node, $4.m_node), $4.m_varDeclarations, $4.m_funcDeclarations, $2.m_features | $4.m_features, $2.m_numConstants + $4.m_numConstants); }
;
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); }
+ DEFAULT ':' { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, 0), 0, 0, 0, 0); }
+ | DEFAULT ':' SourceElements { $$ = createNodeDeclarationInfo<CaseClauseNode*>(new CaseClauseNode(GLOBAL_DATA, 0, $3.m_node), $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_features, $3.m_numConstants); }
;
LabelledStatement:
- IDENT ':' Statement { $3.m_node->pushLabel(*$1);
- $$ = createNodeInfo<StatementNode*>(new LabelNode(*$1, $3.m_node), $3.m_varDeclarations, $3.m_funcDeclarations); }
+ IDENT ':' Statement { LabelNode* node = new LabelNode(GLOBAL_DATA, *$1, $3.m_node);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, $3.m_varDeclarations, $3.m_funcDeclarations, $3.m_features, $3.m_numConstants); }
;
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; }
+ THROW Expr ';' { ThrowNode* node = new ThrowNode(GLOBAL_DATA, $2.m_node);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); DBG($$.m_node, @1, @2);
+ }
+ | THROW Expr error { ThrowNode* node = new ThrowNode(GLOBAL_DATA, $2.m_node);
+ SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column);
+ $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); 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));
+ TRY Block FINALLY Block { $$ = createNodeDeclarationInfo<StatementNode*>(new TryNode(GLOBAL_DATA, $2.m_node, GLOBAL_DATA->propertyNames->nullIdentifier, 0, $4.m_node),
+ mergeDeclarationLists($2.m_varDeclarations, $4.m_varDeclarations),
+ mergeDeclarationLists($2.m_funcDeclarations, $4.m_funcDeclarations),
+ $2.m_features | $4.m_features,
+ $2.m_numConstants + $4.m_numConstants);
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));
+ | TRY Block CATCH '(' IDENT ')' Block { $$ = createNodeDeclarationInfo<StatementNode*>(new TryNode(GLOBAL_DATA, $2.m_node, *$5, $7.m_node, 0),
+ mergeDeclarationLists($2.m_varDeclarations, $7.m_varDeclarations),
+ mergeDeclarationLists($2.m_funcDeclarations, $7.m_funcDeclarations),
+ $2.m_features | $7.m_features | CatchFeature,
+ $2.m_numConstants + $7.m_numConstants);
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));
+ { $$ = createNodeDeclarationInfo<StatementNode*>(new TryNode(GLOBAL_DATA, $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),
+ $2.m_features | $7.m_features | $9.m_features | CatchFeature,
+ $2.m_numConstants + $7.m_numConstants + $9.m_numConstants);
DBG($$.m_node, @1, @2); }
;
DebuggerStatement:
- DEBUGGER ';' { $$ = createNodeInfo<StatementNode*>(new EmptyStatementNode(), 0, 0);
+ DEBUGGER ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0);
DBG($$.m_node, @1, @2); }
- | DEBUGGER error { $$ = createNodeInfo<StatementNode*>(new EmptyStatementNode(), 0, 0);
+ | DEBUGGER error { $$ = createNodeDeclarationInfo<StatementNode*>(new DebuggerStatementNode(GLOBAL_DATA), 0, 0, 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); }
+ FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $6, LEXER->sourceCode($5, $7, @5.first_line)), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | ClosureFeature, 0); DBG($6, @5, @7); }
+ | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
+ {
+ $$ = createNodeInfo(new FuncDeclNode(GLOBAL_DATA, *$2, $7, LEXER->sourceCode($6, $8, @6.first_line), $4.m_node.head), ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features | ClosureFeature, 0);
+ if ($4.m_features & ArgumentsFeature)
+ $7->setUsesArguments();
+ 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); }
+ FUNCTION '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $5, LEXER->sourceCode($4, $6, @4.first_line)), ClosureFeature, 0); DBG($5, @4, @6); }
+ | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
+ {
+ $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $6, LEXER->sourceCode($5, $7, @5.first_line), $3.m_node.head), $3.m_features | ClosureFeature, 0);
+ if ($3.m_features & ArgumentsFeature)
+ $6->setUsesArguments();
+ DBG($6, @5, @7);
+ }
+ | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, *$2, $6, LEXER->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); DBG($6, @5, @7); }
+ | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE
+ {
+ $$ = createNodeInfo(new FuncExprNode(GLOBAL_DATA, *$2, $7, LEXER->sourceCode($6, $8, @6.first_line), $4.m_node.head), $4.m_features | ClosureFeature, 0);
+ if ($4.m_features & ArgumentsFeature)
+ $7->setUsesArguments();
+ DBG($7, @6, @8);
+ }
;
FormalParameterList:
- IDENT { $$.head = new ParameterNode(*$1);
- $$.tail = $$.head; }
- | FormalParameterList ',' IDENT { $$.head = $1.head;
- $$.tail = new ParameterNode($1.tail, *$3); }
+ IDENT { $$.m_node.head = new ParameterNode(GLOBAL_DATA, *$1);
+ $$.m_features = (*$1 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0;
+ $$.m_node.tail = $$.m_node.head; }
+ | FormalParameterList ',' IDENT { $$.m_node.head = $1.m_node.head;
+ $$.m_features = $1.m_features | ((*$3 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0);
+ $$.m_node.tail = new ParameterNode(GLOBAL_DATA, $1.m_node.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);
+ /* not in spec */ { $$ = FunctionBodyNode::create(GLOBAL_DATA, 0, 0, 0, NoFeatures, 0); }
+ | SourceElements { $$ = FunctionBodyNode::create(GLOBAL_DATA, $1.m_node, $1.m_varDeclarations ? &$1.m_varDeclarations->data : 0,
+ $1.m_funcDeclarations ? &$1.m_funcDeclarations->data : 0,
+ $1.m_features, $1.m_numConstants);
// As in mergeDeclarationLists() we have to ref/deref to safely get rid of
// the declaration lists.
if ($1.m_varDeclarations) {
@@ -1018,185 +1221,166 @@ FunctionBody:
;
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); }
+ /* not in spec */ { GLOBAL_DATA->parser->didFinishParsing(new SourceElements(GLOBAL_DATA), 0, 0, NoFeatures, @0.last_line, 0); }
+ | SourceElements { GLOBAL_DATA->parser->didFinishParsing($1.m_node, $1.m_varDeclarations, $1.m_funcDeclarations, $1.m_features,
+ @1.last_line, $1.m_numConstants); }
;
SourceElements:
- SourceElement { $$.m_node = new SourceElements;
+ SourceElement { $$.m_node = new SourceElements(GLOBAL_DATA);
$$.m_node->append($1.m_node);
$$.m_varDeclarations = $1.m_varDeclarations;
$$.m_funcDeclarations = $1.m_funcDeclarations;
+ $$.m_features = $1.m_features;
+ $$.m_numConstants = $1.m_numConstants;
}
| 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);
+ $$.m_features = $1.m_features | $2.m_features;
+ $$.m_numConstants = $1.m_numConstants + $2.m_numConstants;
}
;
SourceElement:
- FunctionDeclaration { $$ = createNodeInfo<StatementNode*>($1, 0, new ParserRefCountedData<DeclarationStacks::FunctionStack>); $$.m_funcDeclarations->data.append($1); }
+ FunctionDeclaration { $$ = createNodeDeclarationInfo<StatementNode*>($1.m_node, 0, new ParserRefCountedData<DeclarationStacks::FunctionStack>(GLOBAL_DATA), $1.m_features, 0); $$.m_funcDeclarations->data.append($1.m_node); }
| 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)
+static ExpressionNode* makeAssignNode(void* globalPtr, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end)
{
if (!loc->isLocation())
- return new AssignErrorNode(loc, op, expr);
+ return new AssignErrorNode(GLOBAL_DATA, loc, op, expr, divot, divot - start, end - divot);
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 (op == OpEqual) {
+ AssignResolveNode* node = new AssignResolveNode(GLOBAL_DATA, resolve->identifier(), expr, exprHasAssignments);
+ SET_EXCEPTION_LOCATION(node, start, divot, end);
+ return node;
+ } else
+ return new ReadModifyResolveNode(GLOBAL_DATA, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
}
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);
+ return new AssignBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot());
+ else {
+ ReadModifyBracketNode* node = new ReadModifyBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+ return node;
+ }
}
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);
+ return new AssignDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot());
+
+ ReadModifyDotNode* node = new ReadModifyDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
}
-static ExpressionNode* makePrefixNode(ExpressionNode* expr, Operator op)
-{
+static ExpressionNode* makePrefixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end)
+{
if (!expr->isLocation())
- return new PrefixErrorNode(expr, op);
+ return new PrefixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot);
if (expr->isResolveNode()) {
ResolveNode* resolve = static_cast<ResolveNode*>(expr);
- if (op == OpPlusPlus)
- return new PreIncResolveNode(resolve->identifier());
- else
- return new PreDecResolveNode(resolve->identifier());
+ return new PrefixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot);
}
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());
+ PrefixBracketNode* node = new PrefixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->startOffset());
+ return node;
}
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());
+ PrefixDotNode* node = new PrefixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->startOffset());
+ return node;
}
-static ExpressionNode* makePostfixNode(ExpressionNode* expr, Operator op)
+static ExpressionNode* makePostfixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end)
{
if (!expr->isLocation())
- return new PostfixErrorNode(expr, op);
+ return new PostfixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot);
if (expr->isResolveNode()) {
ResolveNode* resolve = static_cast<ResolveNode*>(expr);
- if (op == OpPlusPlus)
- return new PostIncResolveNode(resolve->identifier());
- else
- return new PostDecResolveNode(resolve->identifier());
+ return new PostfixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot);
}
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());
+ PostfixBracketNode* node = new PostfixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+ return node;
+
}
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());
+ PostfixDotNode* node = new PostfixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return node;
}
-static ExpressionNode* makeFunctionCallNode(ExpressionNode* func, ArgumentsNode* args)
+static ExpressionNodeInfo makeFunctionCallNode(void* globalPtr, ExpressionNodeInfo func, ArgumentsNodeInfo args, int start, int divot, int end)
{
- if (!func->isLocation())
- return new FunctionCallValueNode(func, args);
- if (func->isResolveNode()) {
- ResolveNode* resolve = static_cast<ResolveNode*>(func);
- return new FunctionCallResolveNode(resolve->identifier(), args);
+ CodeFeatures features = func.m_features | args.m_features;
+ int numConstants = func.m_numConstants + args.m_numConstants;
+ if (!func.m_node->isLocation())
+ return createNodeInfo<ExpressionNode*>(new FunctionCallValueNode(GLOBAL_DATA, func.m_node, args.m_node, divot, divot - start, end - divot), features, numConstants);
+ if (func.m_node->isResolveNode()) {
+ ResolveNode* resolve = static_cast<ResolveNode*>(func.m_node);
+ const Identifier& identifier = resolve->identifier();
+ if (identifier == GLOBAL_DATA->propertyNames->eval)
+ return createNodeInfo<ExpressionNode*>(new EvalFunctionCallNode(GLOBAL_DATA, args.m_node, divot, divot - start, end - divot), EvalFeature | features, numConstants);
+ return createNodeInfo<ExpressionNode*>(new FunctionCallResolveNode(GLOBAL_DATA, identifier, args.m_node, divot, divot - start, end - divot), features, numConstants);
}
- if (func->isBracketAccessorNode()) {
- BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func);
- return new FunctionCallBracketNode(bracket->base(), bracket->subscript(), args);
+ if (func.m_node->isBracketAccessorNode()) {
+ BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func.m_node);
+ FunctionCallBracketNode* node = new FunctionCallBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), args.m_node, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(bracket->divot(), bracket->endOffset());
+ return createNodeInfo<ExpressionNode*>(node, features, numConstants);
}
- ASSERT(func->isDotAccessorNode());
- DotAccessorNode* dot = static_cast<DotAccessorNode*>(func);
- return new FunctionCallDotNode(dot->base(), dot->identifier(), args);
+ ASSERT(func.m_node->isDotAccessorNode());
+ DotAccessorNode* dot = static_cast<DotAccessorNode*>(func.m_node);
+ FunctionCallDotNode* node = new FunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot);
+ node->setSubexpressionInfo(dot->divot(), dot->endOffset());
+ return createNodeInfo<ExpressionNode*>(node, features, numConstants);
}
-static ExpressionNode* makeTypeOfNode(ExpressionNode* expr)
+static ExpressionNode* makeTypeOfNode(void* globalPtr, ExpressionNode* expr)
{
if (expr->isResolveNode()) {
ResolveNode* resolve = static_cast<ResolveNode*>(expr);
- return new TypeOfResolveNode(resolve->identifier());
+ return new TypeOfResolveNode(GLOBAL_DATA, resolve->identifier());
}
- return new TypeOfValueNode(expr);
+ return new TypeOfValueNode(GLOBAL_DATA, expr);
}
-static ExpressionNode* makeDeleteNode(ExpressionNode* expr)
+static ExpressionNode* makeDeleteNode(void* globalPtr, ExpressionNode* expr, int start, int divot, int end)
{
if (!expr->isLocation())
- return new DeleteValueNode(expr);
+ return new DeleteValueNode(GLOBAL_DATA, expr);
if (expr->isResolveNode()) {
ResolveNode* resolve = static_cast<ResolveNode*>(expr);
- return new DeleteResolveNode(resolve->identifier());
+ return new DeleteResolveNode(GLOBAL_DATA, resolve->identifier(), divot, divot - start, end - divot);
}
if (expr->isBracketAccessorNode()) {
BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr);
- return new DeleteBracketNode(bracket->base(), bracket->subscript());
+ return new DeleteBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), divot, divot - start, end - divot);
}
ASSERT(expr->isDotAccessorNode());
DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr);
- return new DeleteDotNode(dot->base(), dot->identifier());
+ return new DeleteDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), divot, divot - start, end - divot);
}
-static PropertyNode* makeGetterOrSetterPropertyNode(const Identifier& getOrSet, const Identifier& name, ParameterNode* params, FunctionBodyNode* body)
+static PropertyNode* makeGetterOrSetterPropertyNode(void* globalPtr, const Identifier& getOrSet, const Identifier& name, ParameterNode* params, FunctionBodyNode* body, const SourceCode& source)
{
PropertyNode::Type type;
if (getOrSet == "get")
@@ -1205,10 +1389,10 @@ static PropertyNode* makeGetterOrSetterPropertyNode(const Identifier& getOrSet,
type = PropertyNode::Setter;
else
return 0;
- return new PropertyNode(name, new FuncExprNode(CommonIdentifiers::shared()->nullIdentifier, body, params), type);
+ return new PropertyNode(GLOBAL_DATA, name, new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, body, source, params), type);
}
-static ExpressionNode* makeNegateNode(ExpressionNode* n)
+static ExpressionNode* makeNegateNode(void* globalPtr, ExpressionNode* n)
{
if (n->isNumber()) {
NumberNode* number = static_cast<NumberNode*>(n);
@@ -1219,15 +1403,80 @@ static ExpressionNode* makeNegateNode(ExpressionNode* n)
}
}
- return new NegateNode(n);
+ return new NegateNode(GLOBAL_DATA, n);
}
-static NumberNode* makeNumberNode(double d)
+static NumberNode* makeNumberNode(void* globalPtr, double d)
{
JSValue* value = JSImmediate::from(d);
if (value)
- return new ImmediateNumberNode(value, d);
- return new NumberNode(d);
+ return new ImmediateNumberNode(GLOBAL_DATA, value, d);
+ return new NumberNode(GLOBAL_DATA, d);
+}
+
+static ExpressionNode* makeBitwiseNotNode(void* globalPtr, ExpressionNode* expr)
+{
+ if (expr->isNumber())
+ return makeNumberNode(globalPtr, ~toInt32(static_cast<NumberNode*>(expr)->value()));
+ return new BitwiseNotNode(GLOBAL_DATA, expr);
+}
+
+static ExpressionNode* makeMultNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value());
+
+ if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1)
+ return new UnaryPlusNode(GLOBAL_DATA, expr2);
+
+ if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1)
+ return new UnaryPlusNode(GLOBAL_DATA, expr1);
+
+ return new MultNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
+}
+
+static ExpressionNode* makeDivNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value());
+ return new DivNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
+}
+
+static ExpressionNode* makeAddNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value());
+ return new AddNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
+}
+
+static ExpressionNode* makeSubNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ expr1 = expr1->stripUnaryPlus();
+ expr2 = expr2->stripUnaryPlus();
+
+ if (expr1->isNumber() && expr2->isNumber())
+ return makeNumberNode(globalPtr, static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value());
+ return new SubNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
+}
+
+static ExpressionNode* makeLeftShiftNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return makeNumberNode(globalPtr, toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new LeftShiftNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
+}
+
+static ExpressionNode* makeRightShiftNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+{
+ if (expr1->isNumber() && expr2->isNumber())
+ return makeNumberNode(globalPtr, toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f));
+ return new RightShiftNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments);
}
/* called by yyparse on error */
@@ -1237,25 +1486,26 @@ int yyerror(const char *)
}
/* may we automatically insert a semicolon ? */
-static bool allowAutomaticSemicolon()
+static bool allowAutomaticSemicolon(Lexer& lexer, int yychar)
{
- return yychar == '}' || yychar == 0 || lexer().prevTerminator();
+ return yychar == CLOSEBRACE || yychar == 0 || lexer.prevTerminator();
}
-static ExpressionNode* combineVarInitializers(ExpressionNode* list, AssignResolveNode* init)
+static ExpressionNode* combineVarInitializers(void* globalPtr, ExpressionNode* list, AssignResolveNode* init)
{
if (!list)
return init;
- return new VarDeclCommaNode(list, init);
+ return new VarDeclCommaNode(GLOBAL_DATA, 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)
+static StatementNode* makeVarStatementNode(void* globalPtr, ExpressionNode* expr)
{
if (!expr)
- return new EmptyStatementNode();
- return new VarStatementNode(expr);
+ return new EmptyStatementNode(GLOBAL_DATA);
+ return new VarStatementNode(GLOBAL_DATA, expr);
}
+#undef GLOBAL_DATA
diff --git a/JavaScriptCore/kjs/identifier.cpp b/JavaScriptCore/kjs/identifier.cpp
index 3fa01ad..50a6cc3 100644
--- a/JavaScriptCore/kjs/identifier.cpp
+++ b/JavaScriptCore/kjs/identifier.cpp
@@ -1,6 +1,5 @@
/*
- * This file is part of the KDE libraries
- * Copyright (C) 2003 Apple Computer, Inc
+ * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -20,103 +19,103 @@
*/
#include "config.h"
-
#include "identifier.h"
-#include "JSLock.h"
+#include "ExecState.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 {
+namespace JSC {
- template<typename T> struct DefaultHash;
- template<typename T> struct StrHash;
+typedef HashMap<const char*, RefPtr<UString::Rep>, PtrHash<const char*> > LiteralIdentifierTable;
- 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;
- };
+class IdentifierTable {
+public:
+ ~IdentifierTable()
+ {
+ HashSet<UString::Rep*>::iterator end = m_table.end();
+ for (HashSet<UString::Rep*>::iterator iter = m_table.begin(); iter != end; ++iter)
+ (*iter)->setIdentifierTable(0);
+ }
+
+ std::pair<HashSet<UString::Rep*>::iterator, bool> add(UString::Rep* value)
+ {
+ std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add(value);
+ (*result.first)->setIdentifierTable(this);
+ return result;
+ }
- template<> struct DefaultHash<KJS::UString::Rep *> {
- typedef StrHash<KJS::UString::Rep *> Hash;
- };
+ template<typename U, typename V>
+ std::pair<HashSet<UString::Rep*>::iterator, bool> add(U value)
+ {
+ std::pair<HashSet<UString::Rep*>::iterator, bool> result = m_table.add<U, V>(value);
+ (*result.first)->setIdentifierTable(this);
+ return result;
+ }
-}
+ void remove(UString::Rep* r) { m_table.remove(r); }
-namespace KJS {
+ LiteralIdentifierTable& literalTable() { return m_literalTable; }
-typedef HashSet<UString::Rep *> IdentifierTable;
-static IdentifierTable *table;
+private:
+ HashSet<UString::Rep*> m_table;
+ LiteralIdentifierTable m_literalTable;
+};
-static inline IdentifierTable& identifierTable()
+IdentifierTable* createIdentifierTable()
{
- ASSERT(JSLock::lockCount() > 0);
-
- if (!table)
- table = new IdentifierTable;
- return *table;
+ return new IdentifierTable;
}
+void deleteIdentifierTable(IdentifierTable* table)
+{
+ delete table;
+}
-bool Identifier::equal(const UString::Rep *r, const char *s)
+bool Identifier::equal(const UString::Rep* r, const char* s)
{
int length = r->len;
- const UChar *d = r->data();
+ const UChar* d = r->data();
for (int i = 0; i != length; ++i)
- if (d[i].uc != (unsigned char)s[i])
+ if (d[i] != (unsigned char)s[i])
return false;
return s[length] == 0;
}
-bool Identifier::equal(const UString::Rep *r, const UChar *s, int length)
+bool Identifier::equal(const UString::Rep* r, const UChar* s, int length)
{
if (r->len != length)
return false;
- const UChar *d = r->data();
+ 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)
+ if (d[i] != s[i])
return false;
return true;
}
struct CStringTranslator
{
- static unsigned hash(const char *c)
+ static unsigned hash(const char* c)
{
return UString::Rep::computeHash(c);
}
- static bool equal(UString::Rep *r, const char *s)
+ 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)
+ 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));
+ UChar* d = static_cast<UChar*>(fastMalloc(sizeof(UChar) * length));
for (size_t i = 0; i != length; i++)
- d[i] = c[i];
+ d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
- UString::Rep *r = UString::Rep::create(d, static_cast<int>(length)).releaseRef();
- r->isIdentifier = 1;
+ UString::Rep* r = UString::Rep::create(d, static_cast<int>(length)).releaseRef();
r->rc = 0;
r->_hash = hash;
@@ -124,23 +123,39 @@ struct CStringTranslator
}
};
-PassRefPtr<UString::Rep> Identifier::add(const char *c)
+PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const char* c)
{
if (!c) {
UString::Rep::null.hash();
return &UString::Rep::null;
}
-
if (!c[0]) {
UString::Rep::empty.hash();
return &UString::Rep::empty;
}
-
- return *identifierTable().add<const char *, CStringTranslator>(c).first;
+ if (!c[1])
+ return add(globalData, globalData->smallStrings.singleCharacterStringRep(static_cast<unsigned char>(c[0])));
+
+ IdentifierTable& identifierTable = *globalData->identifierTable;
+ LiteralIdentifierTable& literalIdentifierTable = identifierTable.literalTable();
+
+ const LiteralIdentifierTable::iterator& iter = literalIdentifierTable.find(c);
+ if (iter != literalIdentifierTable.end())
+ return iter->second;
+
+ UString::Rep* addedString = *identifierTable.add<const char*, CStringTranslator>(c).first;
+ literalIdentifierTable.add(c, addedString);
+
+ return addedString;
+}
+
+PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const char* c)
+{
+ return add(&exec->globalData(), c);
}
struct UCharBuffer {
- const UChar *s;
+ const UChar* s;
unsigned int length;
};
@@ -151,19 +166,18 @@ struct UCharBufferTranslator
return UString::Rep::computeHash(buf.s, buf.length);
}
- static bool equal(UString::Rep *str, const UCharBuffer& buf)
+ 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)
+ static void translate(UString::Rep*& location, const UCharBuffer& buf, unsigned hash)
{
- UChar *d = static_cast<UChar *>(fastMalloc(sizeof(UChar) * buf.length));
+ 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;
+ UString::Rep* r = UString::Rep::create(d, buf.length).releaseRef();
r->rc = 0;
r->_hash = hash;
@@ -171,35 +185,79 @@ struct UCharBufferTranslator
}
};
-PassRefPtr<UString::Rep> Identifier::add(const UChar *s, int length)
+PassRefPtr<UString::Rep> Identifier::add(JSGlobalData* globalData, const UChar* s, int length)
{
+ if (length == 1) {
+ UChar c = s[0];
+ if (c <= 0xFF)
+ return add(globalData, globalData->smallStrings.singleCharacterStringRep(c));
+ }
if (!length) {
UString::Rep::empty.hash();
return &UString::Rep::empty;
}
-
UCharBuffer buf = {s, length};
- return *identifierTable().add<UCharBuffer, UCharBufferTranslator>(buf).first;
+ return *globalData->identifierTable->add<UCharBuffer, UCharBufferTranslator>(buf).first;
}
-PassRefPtr<UString::Rep> Identifier::addSlowCase(UString::Rep *r)
+PassRefPtr<UString::Rep> Identifier::add(ExecState* exec, const UChar* s, int length)
{
- ASSERT(!r->isIdentifier);
+ return add(&exec->globalData(), s, length);
+}
- if (r->len == 0) {
+PassRefPtr<UString::Rep> Identifier::addSlowCase(JSGlobalData* globalData, UString::Rep* r)
+{
+ ASSERT(!r->identifierTable());
+ if (r->len == 1) {
+ UChar c = r->data()[0];
+ if (c <= 0xFF)
+ r = globalData->smallStrings.singleCharacterStringRep(c);
+ if (r->identifierTable()) {
+#ifndef NDEBUG
+ checkSameIdentifierTable(globalData, r);
+#endif
+ return r;
+ }
+ }
+ if (!r->len) {
UString::Rep::empty.hash();
return &UString::Rep::empty;
}
+ return *globalData->identifierTable->add(r).first;
+}
+
+PassRefPtr<UString::Rep> Identifier::addSlowCase(ExecState* exec, UString::Rep* r)
+{
+ return addSlowCase(&exec->globalData(), r);
+}
- UString::Rep *result = *identifierTable().add(r).first;
- if (result == r)
- r->isIdentifier = true;
- return result;
+void Identifier::remove(UString::Rep* r)
+{
+ r->identifierTable()->remove(r);
}
-void Identifier::remove(UString::Rep *r)
+#ifndef NDEBUG
+
+void Identifier::checkSameIdentifierTable(ExecState* exec, UString::Rep* rep)
{
- identifierTable().remove(r);
+ ASSERT(rep->identifierTable() == exec->globalData().identifierTable);
}
-} // namespace KJS
+void Identifier::checkSameIdentifierTable(JSGlobalData* globalData, UString::Rep* rep)
+{
+ ASSERT(rep->identifierTable() == globalData->identifierTable);
+}
+
+#else
+
+void Identifier::checkSameIdentifierTable(ExecState*, UString::Rep*)
+{
+}
+
+void Identifier::checkSameIdentifierTable(JSGlobalData*, UString::Rep*)
+{
+}
+
+#endif
+
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/identifier.h b/JavaScriptCore/kjs/identifier.h
index fc43344..a79dd92 100644
--- a/JavaScriptCore/kjs/identifier.h
+++ b/JavaScriptCore/kjs/identifier.h
@@ -21,31 +21,39 @@
#ifndef KJS_IDENTIFIER_H
#define KJS_IDENTIFIER_H
+#include "JSGlobalData.h"
#include "ustring.h"
-namespace KJS {
+namespace JSC {
+
+ class ExecState;
class Identifier {
- friend class PropertyMap;
+ friend class StructureID;
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())) { }
+
+ Identifier(ExecState* exec, const char* s) : _ustring(add(exec, s)) { } // Only to be used with string literals.
+ Identifier(ExecState* exec, const UChar* s, int length) : _ustring(add(exec, s, length)) { }
+ Identifier(ExecState* exec, UString::Rep* rep) : _ustring(add(exec, rep)) { }
+ Identifier(ExecState* exec, const UString& s) : _ustring(add(exec, s.rep())) { }
+
+ Identifier(JSGlobalData* globalData, const char* s) : _ustring(add(globalData, s)) { } // Only to be used with string literals.
+ Identifier(JSGlobalData* globalData, const UChar* s, int length) : _ustring(add(globalData, s, length)) { }
+ Identifier(JSGlobalData* globalData, UString::Rep* rep) : _ustring(add(globalData, rep)) { }
+ Identifier(JSGlobalData* globalData, const UString& s) : _ustring(add(globalData, s.rep())) { }
// Special constructor for cases where we overwrite an object in place.
Identifier(PlacementNewAdoptType) : _ustring(PlacementNewAdopt) { }
const UString& ustring() const { return _ustring; }
- 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)); }
+ static Identifier from(ExecState* exec, unsigned y) { return Identifier(exec, UString::from(y)); }
bool isNull() const { return _ustring.isNull(); }
bool isEmpty() const { return _ustring.isEmpty(); }
@@ -61,40 +69,72 @@ namespace KJS {
friend bool operator==(const Identifier&, const char*);
- static void remove(UString::Rep* );
+ 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*);
+ static bool equal(const UString::Rep* a, const UString::Rep* b) { return JSC::equal(a, b); }
+
+ static PassRefPtr<UString::Rep> add(ExecState*, const char*); // Only to be used with string literals.
+ static PassRefPtr<UString::Rep> add(JSGlobalData*, const char*); // Only to be used with string literals.
+
+ static void initializeIdentifierThreading();
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)
+ static bool equal(const Identifier& a, const Identifier& b) { return a._ustring.rep() == b._ustring.rep(); }
+ static bool equal(const Identifier& a, const char* b) { return equal(a._ustring.rep(), b); }
+
+ static PassRefPtr<UString::Rep> add(ExecState*, const UChar*, int length);
+ static PassRefPtr<UString::Rep> add(JSGlobalData*, const UChar*, int length);
+
+ static PassRefPtr<UString::Rep> add(ExecState* exec, UString::Rep* r)
+ {
+ if (r->identifierTable()) {
+#ifndef NDEBUG
+ checkSameIdentifierTable(exec, r);
+#endif
+ return r;
+ }
+ return addSlowCase(exec, r);
+ }
+ static PassRefPtr<UString::Rep> add(JSGlobalData* globalData, UString::Rep* r)
{
- if (r->isIdentifier)
+ if (r->identifierTable()) {
+#ifndef NDEBUG
+ checkSameIdentifierTable(globalData, r);
+#endif
return r;
- return addSlowCase(r);
+ }
+ return addSlowCase(globalData, r);
}
- static PassRefPtr<UString::Rep> addSlowCase(UString::Rep *r);
+
+ static PassRefPtr<UString::Rep> addSlowCase(ExecState*, UString::Rep* r);
+ static PassRefPtr<UString::Rep> addSlowCase(JSGlobalData*, UString::Rep* r);
+
+ static void checkSameIdentifierTable(ExecState*, UString::Rep*);
+ static void checkSameIdentifierTable(JSGlobalData*, UString::Rep*);
};
inline bool operator==(const Identifier& a, const Identifier& b)
- { return Identifier::equal(a, b); }
+ {
+ return Identifier::equal(a, b);
+ }
inline bool operator!=(const Identifier& a, const Identifier& b)
- { return !Identifier::equal(a, b); }
+ {
+ return !Identifier::equal(a, b);
+ }
inline bool operator==(const Identifier& a, const char* b)
- { return Identifier::equal(a, b); }
+ {
+ return Identifier::equal(a, b);
+ }
+
+ IdentifierTable* createIdentifierTable();
+ void deleteIdentifierTable(IdentifierTable*);
-} // namespace KJS
+} // namespace JSC
#endif // KJS_IDENTIFIER_H
diff --git a/JavaScriptCore/kjs/internal.cpp b/JavaScriptCore/kjs/internal.cpp
deleted file mode 100644
index 5482b48..0000000
--- a/JavaScriptCore/kjs/internal.cpp
+++ /dev/null
@@ -1,302 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 51438b3..0000000
--- a/JavaScriptCore/kjs/internal.h
+++ /dev/null
@@ -1,122 +0,0 @@
-// -*- 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;
- isAborted = false;
- }
-
- void abort() { isAborted = true; }
- bool aborted() const { return isAborted; }
-
- AttachedGlobalObject* globalObjects;
- bool isAborted;
- };
-
-#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
index 0d515ac..1188349 100644
--- a/JavaScriptCore/kjs/interpreter.cpp
+++ b/JavaScriptCore/kjs/interpreter.cpp
@@ -1,6 +1,4 @@
-// -*- 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, 2007 Apple Inc.
@@ -27,131 +25,54 @@
#include "ExecState.h"
#include "JSGlobalObject.h"
+#include "JSLock.h"
+#include "Machine.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 "completion.h"
+#include "Debugger.h"
#include <stdio.h>
-#include <wtf/Assertions.h>
-namespace KJS {
+#if !PLATFORM(WIN_OS)
+#include <unistd.h>
+#endif
-Completion Interpreter::checkSyntax(ExecState* exec, const UString& sourceURL, int startingLineNumber, const UString& code)
-{
- return checkSyntax(exec, sourceURL, startingLineNumber, code.data(), code.size());
-}
+namespace JSC {
-Completion Interpreter::checkSyntax(ExecState* exec, const UString& sourceURL, int startingLineNumber, const UChar* code, int codeLength)
+Completion Interpreter::checkSyntax(ExecState* exec, const SourceCode& source)
{
- JSLock lock;
+ JSLock lock(exec);
int errLine;
UString errMsg;
- RefPtr<ProgramNode> progNode = parser().parse<ProgramNode>(sourceURL, startingLineNumber, code, codeLength, 0, &errLine, &errMsg);
+
+ RefPtr<ProgramNode> progNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg);
if (!progNode)
- return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, 0, sourceURL));
+ return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url()));
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)
+Completion Interpreter::evaluate(ExecState* exec, ScopeChain& scopeChain, const SourceCode& source, JSValue* thisValue)
{
- JSLock lock;
+ JSLock lock(exec);
- 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
- }
+ RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg);
- return res;
-}
+ if (!programNode)
+ return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url()));
-static bool printExceptions = false;
+ JSObject* thisObj = (!thisValue || thisValue->isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue->toObject(exec);
-bool Interpreter::shouldPrintExceptions()
-{
- return printExceptions;
-}
+ JSValue* exception = noValue();
+ JSValue* result = exec->machine()->execute(programNode.get(), exec, scopeChain.node(), thisObj, &exception);
-void Interpreter::setShouldPrintExceptions(bool print)
-{
- printExceptions = print;
+ if (exception) {
+ if (exception->isObject() && asObject(exception)->isWatchdogException())
+ return Completion(Interrupted, result);
+ return Completion(Throw, exception);
+ }
+ return Completion(Normal, result);
}
-} // namespace KJS
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/interpreter.h b/JavaScriptCore/kjs/interpreter.h
index 79b9398..0366063 100644
--- a/JavaScriptCore/kjs/interpreter.h
+++ b/JavaScriptCore/kjs/interpreter.h
@@ -23,14 +23,16 @@
#ifndef KJS_Interpreter_h
#define KJS_Interpreter_h
-namespace KJS {
+#include "JSValue.h"
+#include <wtf/PassRefPtr.h>
+#include <wtf/unicode/Unicode.h>
+
+namespace JSC {
class Completion;
class ExecState;
- class JSValue;
- class UString;
-
- struct UChar;
+ class ScopeChain;
+ class SourceCode;
class Interpreter {
public:
@@ -41,8 +43,7 @@ namespace KJS {
* @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);
+ static Completion checkSyntax(ExecState*, const SourceCode&);
/**
* Evaluates the supplied ECMAScript code.
@@ -55,17 +56,13 @@ namespace KJS {
* 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
+ * @param thisValue 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);
+ static Completion evaluate(ExecState*, ScopeChain&, const SourceCode&, JSValue* thisValue = noValue());
};
-} // namespace KJS
+} // namespace JSC
#endif // KJS_Interpreter_h
diff --git a/JavaScriptCore/kjs/jsc.pro b/JavaScriptCore/kjs/jsc.pro
new file mode 100644
index 0000000..2a30d65
--- /dev/null
+++ b/JavaScriptCore/kjs/jsc.pro
@@ -0,0 +1,35 @@
+TEMPLATE = app
+TARGET = jsc
+DESTDIR = ..
+SOURCES = Shell.cpp
+QT -= gui
+INCLUDEPATH += $$PWD/.. \
+ $$PWD \
+ $$PWD/../bindings \
+ $$PWD/../bindings/c \
+ $$PWD/../wtf \
+ $$PWD/../VM
+CONFIG -= app_bundle
+DEFINES += BUILDING_QT__
+CONFIG += building-libs
+
+CONFIG(release) {
+ DEFINES += NDEBUG USE_SYSTEM_MALLOC
+}
+
+include($$PWD/../../WebKit.pri)
+
+CONFIG += link_pkgconfig
+
+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)
+
+lessThan(QT_MINOR_VERSION, 4) {
+ DEFINES += QT_BEGIN_NAMESPACE="" QT_END_NAMESPACE=""
+}
diff --git a/JavaScriptCore/kjs/lexer.cpp b/JavaScriptCore/kjs/lexer.cpp
index c4d327f..7313b12 100644
--- a/JavaScriptCore/kjs/lexer.cpp
+++ b/JavaScriptCore/kjs/lexer.cpp
@@ -1,7 +1,6 @@
-// -*- c-basic-offset: 2 -*-
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2006, 2007 Apple Inc. All Rights Reserved.
+ * Copyright (C) 2006, 2007, 2008 Apple Inc. All Rights Reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
*
* This library is free software; you can redistribute it and/or
@@ -25,9 +24,10 @@
#include "lexer.h"
#include "dtoa.h"
-#include "function.h"
+#include "JSFunction.h"
#include "nodes.h"
#include "NodeInfo.h"
+#include "JSGlobalObjectFunctions.h"
#include <ctype.h>
#include <limits.h>
#include <string.h>
@@ -38,7 +38,7 @@ using namespace WTF;
using namespace Unicode;
// we can't specify the namespace in yacc's C output, so do it here
-using namespace KJS;
+using namespace JSC;
#ifndef KDE_USE_FINAL
#include "grammar.h"
@@ -47,46 +47,39 @@ using namespace KJS;
#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()
+int kjsyylex(void* lvalp, void* llocp, void* globalData)
{
- return lexer().lex();
+ return static_cast<JSGlobalData*>(globalData)->lexer->lex(lvalp, llocp);
}
-namespace KJS {
+namespace JSC {
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()
+Lexer::Lexer(JSGlobalData* globalData)
: 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_restrKeyword(false)
+ , m_eatNextIdentifier(false)
+ , m_stackToken(-1)
+ , m_lastToken(-1)
+ , m_position(0)
+ , m_code(0)
+ , m_length(0)
+ , m_atLineStart(true)
+ , m_current(0)
+ , m_next1(0)
+ , m_next2(0)
+ , m_next3(0)
+ , m_currentOffset(0)
+ , m_nextOffset1(0)
+ , m_nextOffset2(0)
+ , m_nextOffset3(0)
+ , m_globalData(globalData)
+ , m_mainTable(JSC::mainTable)
{
m_buffer8.reserveCapacity(initialReadBufferCapacity);
m_buffer16.reserveCapacity(initialReadBufferCapacity);
@@ -94,708 +87,746 @@ Lexer::Lexer()
m_identifiers.reserveCapacity(initialStringTableCapacity);
}
-void Lexer::setCode(int startingLineNumber, const KJS::UChar *c, unsigned int len)
+Lexer::~Lexer()
+{
+ m_mainTable.deleteTable();
+}
+
+void Lexer::setCode(const SourceCode& source)
{
- 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;
+ yylineno = source.firstLine();
+ m_restrKeyword = false;
+ m_delimited = false;
+ m_eatNextIdentifier = false;
+ m_stackToken = -1;
+ m_lastToken = -1;
+
+ m_position = 0;
+ m_source = &source;
+ m_code = source.data();
+ m_length = source.length();
+ m_skipLF = false;
+ m_skipCR = false;
+ m_error = false;
+ m_atLineStart = true;
+
+ // read first characters
+ shift(4);
}
-void Lexer::shift(unsigned int p)
+void Lexer::shift(unsigned 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;
- }
+ // ECMA-262 calls for stripping Cf characters here, but we only do this for BOM,
+ // see <https://bugs.webkit.org/show_bug.cgi?id=4931>.
+
+ while (p--) {
+ m_current = m_next1;
+ m_next1 = m_next2;
+ m_next2 = m_next3;
+ m_currentOffset = m_nextOffset1;
+ m_nextOffset1 = m_nextOffset2;
+ m_nextOffset2 = m_nextOffset3;
+ do {
+ if (m_position >= m_length) {
+ m_nextOffset3 = m_position;
+ m_position++;
+ m_next3 = -1;
+ break;
+ }
+ m_nextOffset3 = m_position;
+ m_next3 = m_code[m_position++];
+ } while (m_next3 == 0xFEFF);
+ }
}
// called on each new line
void Lexer::nextLine()
{
- yylineno++;
- atLineStart = true;
+ yylineno++;
+ m_atLineStart = true;
}
void Lexer::setDone(State s)
{
- state = s;
- done = true;
+ m_state = s;
+ m_done = true;
}
-int Lexer::lex()
+int Lexer::lex(void* p1, void* p2)
{
- 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);
+ YYSTYPE* lvalp = static_cast<YYSTYPE*>(p1);
+ YYLTYPE* llocp = static_cast<YYLTYPE*>(p2);
+ int token = 0;
+ m_state = Start;
+ unsigned short stringType = 0; // either single or double quotes
+ m_buffer8.clear();
+ m_buffer16.clear();
+ m_done = false;
+ m_terminator = false;
+ m_skipLF = false;
+ m_skipCR = false;
+
+ // did we push a token on the stack previously ?
+ // (after an automatic semicolon insertion)
+ if (m_stackToken >= 0) {
+ setDone(Other);
+ token = m_stackToken;
+ m_stackToken = 0;
}
- 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);
+ int startOffset = m_currentOffset;
+ while (!m_done) {
+ if (m_skipLF && m_current != '\n') // found \r but not \n afterwards
+ m_skipLF = false;
+ if (m_skipCR && m_current != '\r') // found \n but not \r afterwards
+ m_skipCR = false;
+ if (m_skipLF || m_skipCR) { // found \r\n or \n\r -> eat the second one
+ m_skipLF = false;
+ m_skipCR = false;
+ shift(1);
}
- }
- 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);
+ switch (m_state) {
+ case Start:
+ startOffset = m_currentOffset;
+ if (isWhiteSpace()) {
+ // do nothing
+ } else if (m_current == '/' && m_next1 == '/') {
+ shift(1);
+ m_state = InSingleLineComment;
+ } else if (m_current == '/' && m_next1 == '*') {
+ shift(1);
+ m_state = InMultiLineComment;
+ } else if (m_current == -1) {
+ if (!m_terminator && !m_delimited) {
+ // automatic semicolon insertion if program incomplete
+ token = ';';
+ m_stackToken = 0;
+ setDone(Other);
+ } else
+ setDone(Eof);
+ } else if (isLineTerminator()) {
+ nextLine();
+ m_terminator = true;
+ if (m_restrKeyword) {
+ token = ';';
+ setDone(Other);
+ }
+ } else if (m_current == '"' || m_current == '\'') {
+ m_state = InString;
+ stringType = static_cast<unsigned short>(m_current);
+ } else if (isIdentStart(m_current)) {
+ record16(m_current);
+ m_state = InIdentifierOrKeyword;
+ } else if (m_current == '\\')
+ m_state = InIdentifierStartUnicodeEscapeStart;
+ else if (m_current == '0') {
+ record8(m_current);
+ m_state = InNum0;
+ } else if (isDecimalDigit(m_current)) {
+ record8(m_current);
+ m_state = InNum;
+ } else if (m_current == '.' && isDecimalDigit(m_next1)) {
+ record8(m_current);
+ m_state = InDecimal;
+ // <!-- marks the beginning of a line comment (for www usage)
+ } else if (m_current == '<' && m_next1 == '!' && m_next2 == '-' && m_next3 == '-') {
+ shift(3);
+ m_state = InSingleLineComment;
+ // same for -->
+ } else if (m_atLineStart && m_current == '-' && m_next1 == '-' && m_next2 == '>') {
+ shift(2);
+ m_state = InSingleLineComment;
+ } else {
+ token = matchPunctuator(lvalp->intValue, m_current, m_next1, m_next2, m_next3);
+ if (token != -1)
+ setDone(Other);
+ else
+ setDone(Bad);
+ }
+ break;
+ case InString:
+ if (m_current == stringType) {
+ shift(1);
+ setDone(String);
+ } else if (isLineTerminator() || m_current == -1)
+ setDone(Bad);
+ else if (m_current == '\\')
+ m_state = InEscapeSequence;
+ else
+ record16(m_current);
+ break;
+ // Escape Sequences inside of strings
+ case InEscapeSequence:
+ if (isOctalDigit(m_current)) {
+ if (m_current >= '0' && m_current <= '3' &&
+ isOctalDigit(m_next1) && isOctalDigit(m_next2)) {
+ record16(convertOctal(m_current, m_next1, m_next2));
+ shift(2);
+ m_state = InString;
+ } else if (isOctalDigit(m_current) && isOctalDigit(m_next1)) {
+ record16(convertOctal('0', m_current, m_next1));
+ shift(1);
+ m_state = InString;
+ } else if (isOctalDigit(m_current)) {
+ record16(convertOctal('0', '0', m_current));
+ m_state = InString;
+ } else
+ setDone(Bad);
+ } else if (m_current == 'x')
+ m_state = InHexEscape;
+ else if (m_current == 'u')
+ m_state = InUnicodeEscape;
+ else if (isLineTerminator()) {
+ nextLine();
+ m_state = InString;
+ } else {
+ record16(singleEscape(static_cast<unsigned short>(m_current)));
+ m_state = InString;
+ }
+ break;
+ case InHexEscape:
+ if (isHexDigit(m_current) && isHexDigit(m_next1)) {
+ m_state = InString;
+ record16(convertHex(m_current, m_next1));
+ shift(1);
+ } else if (m_current == stringType) {
+ record16('x');
+ shift(1);
+ setDone(String);
+ } else {
+ record16('x');
+ record16(m_current);
+ m_state = InString;
+ }
+ break;
+ case InUnicodeEscape:
+ if (isHexDigit(m_current) && isHexDigit(m_next1) && isHexDigit(m_next2) && isHexDigit(m_next3)) {
+ record16(convertUnicode(m_current, m_next1, m_next2, m_next3));
+ shift(3);
+ m_state = InString;
+ } else if (m_current == stringType) {
+ record16('u');
+ shift(1);
+ setDone(String);
+ } else
+ setDone(Bad);
+ break;
+ case InSingleLineComment:
+ if (isLineTerminator()) {
+ nextLine();
+ m_terminator = true;
+ if (m_restrKeyword) {
+ token = ';';
+ setDone(Other);
+ } else
+ m_state = Start;
+ } else if (m_current == -1)
+ setDone(Eof);
+ break;
+ case InMultiLineComment:
+ if (m_current == -1)
+ setDone(Bad);
+ else if (isLineTerminator())
+ nextLine();
+ else if (m_current == '*' && m_next1 == '/') {
+ m_state = Start;
+ shift(1);
+ }
+ break;
+ case InIdentifierOrKeyword:
+ case InIdentifier:
+ if (isIdentPart(m_current))
+ record16(m_current);
+ else if (m_current == '\\')
+ m_state = InIdentifierPartUnicodeEscapeStart;
+ else
+ setDone(m_state == InIdentifierOrKeyword ? IdentifierOrKeyword : Identifier);
+ break;
+ case InNum0:
+ if (m_current == 'x' || m_current == 'X') {
+ record8(m_current);
+ m_state = InHex;
+ } else if (m_current == '.') {
+ record8(m_current);
+ m_state = InDecimal;
+ } else if (m_current == 'e' || m_current == 'E') {
+ record8(m_current);
+ m_state = InExponentIndicator;
+ } else if (isOctalDigit(m_current)) {
+ record8(m_current);
+ m_state = InOctal;
+ } else if (isDecimalDigit(m_current)) {
+ record8(m_current);
+ m_state = InDecimal;
+ } else
+ setDone(Number);
+ break;
+ case InHex:
+ if (isHexDigit(m_current))
+ record8(m_current);
+ else
+ setDone(Hex);
+ break;
+ case InOctal:
+ if (isOctalDigit(m_current))
+ record8(m_current);
+ else if (isDecimalDigit(m_current)) {
+ record8(m_current);
+ m_state = InDecimal;
+ } else
+ setDone(Octal);
+ break;
+ case InNum:
+ if (isDecimalDigit(m_current))
+ record8(m_current);
+ else if (m_current == '.') {
+ record8(m_current);
+ m_state = InDecimal;
+ } else if (m_current == 'e' || m_current == 'E') {
+ record8(m_current);
+ m_state = InExponentIndicator;
+ } else
+ setDone(Number);
+ break;
+ case InDecimal:
+ if (isDecimalDigit(m_current))
+ record8(m_current);
+ else if (m_current == 'e' || m_current == 'E') {
+ record8(m_current);
+ m_state = InExponentIndicator;
+ } else
+ setDone(Number);
+ break;
+ case InExponentIndicator:
+ if (m_current == '+' || m_current == '-')
+ record8(m_current);
+ else if (isDecimalDigit(m_current)) {
+ record8(m_current);
+ m_state = InExponent;
+ } else
+ setDone(Bad);
+ break;
+ case InExponent:
+ if (isDecimalDigit(m_current))
+ record8(m_current);
+ else
+ setDone(Number);
+ break;
+ case InIdentifierStartUnicodeEscapeStart:
+ if (m_current == 'u')
+ m_state = InIdentifierStartUnicodeEscape;
+ else
+ setDone(Bad);
+ break;
+ case InIdentifierPartUnicodeEscapeStart:
+ if (m_current == 'u')
+ m_state = InIdentifierPartUnicodeEscape;
+ else
+ setDone(Bad);
+ break;
+ case InIdentifierStartUnicodeEscape:
+ if (!isHexDigit(m_current) || !isHexDigit(m_next1) || !isHexDigit(m_next2) || !isHexDigit(m_next3)) {
+ setDone(Bad);
+ break;
+ }
+ token = convertUnicode(m_current, m_next1, m_next2, m_next3);
+ shift(3);
+ if (!isIdentStart(token)) {
+ setDone(Bad);
+ break;
+ }
+ record16(token);
+ m_state = InIdentifier;
+ break;
+ case InIdentifierPartUnicodeEscape:
+ if (!isHexDigit(m_current) || !isHexDigit(m_next1) || !isHexDigit(m_next2) || !isHexDigit(m_next3)) {
+ setDone(Bad);
+ break;
+ }
+ token = convertUnicode(m_current, m_next1, m_next2, m_next3);
+ shift(3);
+ if (!isIdentPart(token)) {
+ setDone(Bad);
+ break;
+ }
+ record16(token);
+ m_state = InIdentifier;
+ break;
+ default:
+ ASSERT(!"Unhandled state in switch statement");
}
- } 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');
+
+ // move on to the next character
+ if (!m_done)
+ shift(1);
+ if (m_state != Start && m_state != InSingleLineComment)
+ m_atLineStart = false;
+ }
+
+ // no identifiers allowed directly after numeric literal, e.g. "3in" is bad
+ if ((m_state == Number || m_state == Octal || m_state == Hex) && isIdentStart(m_current))
+ m_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());
+ fprintf(stderr, "line: %d ", lineNo());
+ fprintf(stderr, "yytext (%x): ", m_buffer8[0]);
+ fprintf(stderr, "%s ", m_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);
- }
+ double dval = 0;
+ if (m_state == Number)
+ dval = strtod(m_buffer8.data(), 0L);
+ else if (m_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);
+ 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';
- }
+ m_state = Number;
+ } else if (m_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);
+ if (dval >= mantissaOverflowLowerBound)
+ dval = parseIntOverflow(m_buffer8.data() + 1, p - (m_buffer8.data() + 2), 8);
- state = Number;
- }
+ m_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)");
- }
+ switch (m_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:
+ if (m_state != Identifier)
+ m_eatNextIdentifier = false;
+
+ m_restrKeyword = false;
+ m_delimited = false;
+ llocp->first_line = yylineno;
+ llocp->last_line = yylineno;
+ llocp->first_column = startOffset;
+ llocp->last_column = m_currentOffset;
+ switch (m_state) {
+ case Eof:
+ token = 0;
+ break;
+ case Other:
+ if (token == '}' || token == ';')
+ m_delimited = true;
+ break;
+ case Identifier:
+ // Apply anonymous-function hack below (eat the identifier).
+ if (m_eatNextIdentifier) {
+ m_eatNextIdentifier = false;
+ token = lex(lvalp, llocp);
+ break;
+ }
+ lvalp->ident = makeIdentifier(m_buffer16);
+ token = IDENT;
+ break;
+ case IdentifierOrKeyword: {
+ lvalp->ident = makeIdentifier(m_buffer16);
+ const HashEntry* entry = m_mainTable.entry(m_globalData, *lvalp->ident);
+ if (!entry) {
+ // Lookup for keyword failed, means this is an identifier.
+ token = IDENT;
+ break;
+ }
+ token = entry->lexerValue();
+ // Hack for "f = function somename() { ... }"; too hard to get into the grammar.
+ m_eatNextIdentifier = token == FUNCTION && m_lastToken == '=';
+ if (token == CONTINUE || token == BREAK || token == RETURN || token == THROW)
+ m_restrKeyword = true;
+ break;
+ }
+ case String:
+ // Atomize constant strings in case they're later used in property lookup.
+ lvalp->ident = makeIdentifier(m_buffer16);
+ token = STRING;
+ break;
+ case Number:
+ lvalp->doubleValue = dval;
+ token = NUMBER;
+ break;
+ case Bad:
#ifdef KJS_DEBUG_LEX
- fprintf(stderr, "yylex: ERROR.\n");
+ 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;
+ m_error = true;
+ return -1;
+ default:
+ ASSERT(!"unhandled numeration value in switch");
+ m_error = true;
+ return -1;
+ }
+ m_lastToken = token;
+ return token;
}
bool Lexer::isWhiteSpace() const
{
- return current == '\t' || current == 0x0b || current == 0x0c || isSeparatorSpace(current);
+ return m_current == '\t' || m_current == 0x0b || m_current == 0x0c || isSeparatorSpace(m_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 cr = (m_current == '\r');
+ bool lf = (m_current == '\n');
+ if (cr)
+ m_skipLF = true;
+ else if (lf)
+ m_skipCR = true;
+ return cr || lf || m_current == 0x2028 || m_current == 0x2029;
}
bool Lexer::isIdentStart(int c)
{
- return (category(c) & (Letter_Uppercase | Letter_Lowercase | Letter_Titlecase | Letter_Modifier | Letter_Other))
- || c == '$' || 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 == '_';
+ 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');
+ return (c >= '0' && c <= '9');
}
bool Lexer::isHexDigit(int c)
{
- return (c >= '0' && c <= '9' ||
- c >= 'a' && c <= 'f' ||
- c >= 'A' && c <= 'F');
+ return (c >= '0' && c <= '9'
+ || c >= 'a' && c <= 'f'
+ || c >= 'A' && c <= 'F');
}
bool Lexer::isOctalDigit(int c)
{
- return (c >= '0' && c <= '7');
+ return (c >= '0' && c <= '7');
}
-int Lexer::matchPunctuator(int c1, int c2, int c3, int c4)
+int Lexer::matchPunctuator(int& charPos, 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;
- }
+ if (c1 == '>' && c2 == '>' && c3 == '>' && c4 == '=') {
+ shift(4);
+ return URSHIFTEQUAL;
+ }
+ if (c1 == '=' && c2 == '=' && c3 == '=') {
+ shift(3);
+ return STREQ;
+ }
+ if (c1 == '!' && c2 == '=' && c3 == '=') {
+ shift(3);
+ return STRNEQ;
+ }
+ if (c1 == '>' && c2 == '>' && c3 == '>') {
+ shift(3);
+ return URSHIFT;
+ }
+ if (c1 == '<' && c2 == '<' && c3 == '=') {
+ shift(3);
+ return LSHIFTEQUAL;
+ }
+ if (c1 == '>' && c2 == '>' && c3 == '=') {
+ shift(3);
+ return RSHIFTEQUAL;
+ }
+ if (c1 == '<' && c2 == '=') {
+ shift(2);
+ return LE;
+ }
+ if (c1 == '>' && c2 == '=') {
+ shift(2);
+ return GE;
+ }
+ if (c1 == '!' && c2 == '=') {
+ shift(2);
+ return NE;
+ }
+ if (c1 == '+' && c2 == '+') {
+ shift(2);
+ if (m_terminator)
+ return AUTOPLUSPLUS;
+ return PLUSPLUS;
+ }
+ if (c1 == '-' && c2 == '-') {
+ shift(2);
+ if (m_terminator)
+ return AUTOMINUSMINUS;
+ return MINUSMINUS;
+ }
+ if (c1 == '=' && c2 == '=') {
+ shift(2);
+ return EQEQ;
+ }
+ if (c1 == '+' && c2 == '=') {
+ shift(2);
+ return PLUSEQUAL;
+ }
+ if (c1 == '-' && c2 == '=') {
+ shift(2);
+ return MINUSEQUAL;
+ }
+ if (c1 == '*' && c2 == '=') {
+ shift(2);
+ return MULTEQUAL;
+ }
+ if (c1 == '/' && c2 == '=') {
+ shift(2);
+ return DIVEQUAL;
+ }
+ if (c1 == '&' && c2 == '=') {
+ shift(2);
+ return ANDEQUAL;
+ }
+ if (c1 == '^' && c2 == '=') {
+ shift(2);
+ return XOREQUAL;
+ }
+ if (c1 == '%' && c2 == '=') {
+ shift(2);
+ return MODEQUAL;
+ }
+ if (c1 == '|' && c2 == '=') {
+ shift(2);
+ return OREQUAL;
+ }
+ if (c1 == '<' && c2 == '<') {
+ shift(2);
+ return LSHIFT;
+ }
+ if (c1 == '>' && c2 == '>') {
+ shift(2);
+ return RSHIFT;
+ }
+ if (c1 == '&' && c2 == '&') {
+ shift(2);
+ return AND;
+ }
+ 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 ';':
+ shift(1);
+ return static_cast<int>(c1);
+ case '{':
+ charPos = m_position - 4;
+ shift(1);
+ return OPENBRACE;
+ case '}':
+ charPos = m_position - 4;
+ shift(1);
+ return CLOSEBRACE;
+ 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;
- }
+ 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');
+ 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);
+ 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));
+ return ((convertHex(c1) << 4) + convertHex(c2));
}
-KJS::UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4)
+UChar Lexer::convertUnicode(int c1, int c2, int c3, int c4)
{
- return KJS::UChar((convertHex(c1) << 4) + convertHex(c2),
- (convertHex(c3) << 4) + convertHex(c4));
+ unsigned char highByte = (convertHex(c1) << 4) + convertHex(c2);
+ unsigned char lowByte = (convertHex(c3) << 4) + convertHex(c4);
+ return (highByte << 8 | lowByte);
}
void Lexer::record8(int c)
@@ -812,48 +843,47 @@ void Lexer::record16(int c)
record16(UChar(static_cast<unsigned short>(c)));
}
-void Lexer::record16(KJS::UChar c)
+void Lexer::record16(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;
+ m_buffer16.clear();
+ bool lastWasEscape = false;
+ bool inBrackets = false;
+
+ while (1) {
+ if (isLineTerminator() || m_current == -1)
+ return false;
+ else if (m_current != '/' || lastWasEscape == true || inBrackets == true) {
+ // keep track of '[' and ']'
+ if (!lastWasEscape) {
+ if ( m_current == '[' && !inBrackets )
+ inBrackets = true;
+ if ( m_current == ']' && inBrackets )
+ inBrackets = false;
+ }
+ record16(m_current);
+ lastWasEscape =
+ !lastWasEscape && (m_current == '\\');
+ } else { // end of regexp
+ m_pattern = UString(m_buffer16);
+ m_buffer16.clear();
+ shift(1);
+ break;
}
- 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);
+ while (isIdentPart(m_current)) {
+ record16(m_current);
+ shift(1);
+ }
+ m_flags = UString(m_buffer16);
- return true;
+ return true;
}
void Lexer::clear()
@@ -864,7 +894,7 @@ void Lexer::clear()
m_strings.swap(newStrings);
deleteAllValues(m_identifiers);
- Vector<KJS::Identifier*> newIdentifiers;
+ Vector<JSC::Identifier*> newIdentifiers;
newIdentifiers.reserveCapacity(initialStringTableCapacity);
m_identifiers.swap(newIdentifiers);
@@ -880,18 +910,11 @@ void Lexer::clear()
m_flags = 0;
}
-Identifier* Lexer::makeIdentifier(const Vector<KJS::UChar>& buffer)
+Identifier* Lexer::makeIdentifier(const Vector<UChar>& buffer)
{
- KJS::Identifier* identifier = new KJS::Identifier(buffer.data(), buffer.size());
+ JSC::Identifier* identifier = new JSC::Identifier(m_globalData, 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
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/lexer.h b/JavaScriptCore/kjs/lexer.h
index 1ce27af..16bc4b6 100644
--- a/JavaScriptCore/kjs/lexer.h
+++ b/JavaScriptCore/kjs/lexer.h
@@ -1,4 +1,3 @@
-// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
@@ -24,126 +23,142 @@
#ifndef Lexer_h
#define Lexer_h
+#include "lookup.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
+#include "SourceCode.h"
+
+namespace JSC {
+
+ class Identifier;
+ class RegExp;
+
+ class Lexer : Noncopyable {
+ public:
+ void setCode(const SourceCode&);
+ int lex(void* lvalp, void* llocp);
+
+ int lineNo() const { return yylineno; }
+
+ bool prevTerminator() const { return m_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 m_error; }
+
+ void clear();
+ SourceCode sourceCode(int openBrace, int closeBrace, int firstLine) { return SourceCode(m_source->provider(), m_source->startOffset() + openBrace + 1, m_source->startOffset() + closeBrace, firstLine); }
+
+ private:
+ friend class JSGlobalData;
+ Lexer(JSGlobalData*);
+ ~Lexer();
+
+ void setDone(State);
+ void shift(unsigned int p);
+ void nextLine();
+ int lookupKeyword(const char *);
+
+ bool isWhiteSpace() const;
+ bool isLineTerminator();
+ static bool isOctalDigit(int);
+
+ int matchPunctuator(int& charPos, 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);
+
+ JSC::Identifier* makeIdentifier(const Vector<UChar>& buffer);
+
+ int yylineno;
+ int yycolumn;
+
+ bool m_done;
+ Vector<char> m_buffer8;
+ Vector<UChar> m_buffer16;
+ bool m_terminator;
+ bool m_restrKeyword;
+ bool m_delimited; // encountered delimiter like "'" and "}" on last run
+ bool m_skipLF;
+ bool m_skipCR;
+ bool m_eatNextIdentifier;
+ int m_stackToken;
+ int m_lastToken;
+
+ State m_state;
+ unsigned int m_position;
+ const SourceCode* m_source;
+ const UChar* m_code;
+ unsigned int m_length;
+ int m_atLineStart;
+ bool m_error;
+
+ // current and following unicode characters (int to allow for -1 for end-of-file marker)
+ int m_current;
+ int m_next1;
+ int m_next2;
+ int m_next3;
+
+ int m_currentOffset;
+ int m_nextOffset1;
+ int m_nextOffset2;
+ int m_nextOffset3;
+
+ Vector<UString*> m_strings;
+ Vector<JSC::Identifier*> m_identifiers;
+
+ JSGlobalData* m_globalData;
+
+ UString m_pattern;
+ UString m_flags;
+
+ const HashTable m_mainTable;
+ };
+
+} // namespace JSC
#endif // Lexer_h
diff --git a/JavaScriptCore/kjs/list.cpp b/JavaScriptCore/kjs/list.cpp
deleted file mode 100644
index 5cc7cc2..0000000
--- a/JavaScriptCore/kjs/list.cpp
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 6a43e08..0000000
--- a/JavaScriptCore/kjs/list.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/*
- * 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
index 95dc5cb..41ac725 100644
--- a/JavaScriptCore/kjs/lookup.cpp
+++ b/JavaScriptCore/kjs/lookup.cpp
@@ -1,7 +1,5 @@
-// -*- c-basic-offset: 2 -*-
/*
- * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2007 Apple Inc. All rights reserved.
+ * 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
@@ -22,60 +20,49 @@
#include "config.h"
#include "lookup.h"
-#include <wtf/Assertions.h>
+#include "PrototypeFunction.h"
-namespace KJS {
+namespace JSC {
-static inline bool keysMatch(const UChar* c, unsigned len, const char* s)
+void HashTable::createTable(JSGlobalData* globalData) const
{
- // 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;
+ ASSERT(!table);
+ HashEntry* entries = new HashEntry[hashSizeMask + 1];
+ for (int i = 0; i <= hashSizeMask; ++i)
+ entries[i].setKey(0);
+ for (int i = 0; values[i].key; ++i) {
+ UString::Rep* identifier = Identifier::add(globalData, values[i].key).releaseRef();
+ int hashIndex = identifier->computedHash() & hashSizeMask;
+ ASSERT(!entries[hashIndex].key());
+ entries[hashIndex].initialize(identifier, values[i].attributes, values[i].value1, values[i].value2);
+ }
+ table = entries;
}
-static inline const HashEntry* findEntry(const struct HashTable* table, unsigned int hash,
- const UChar* c, unsigned int len)
+void HashTable::deleteTable() const
{
- 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;
+ if (table) {
+ for (int i = 0; i != hashSizeMask + 1; ++i) {
+ if (UString::Rep* key = table[i].key())
+ key->deref();
+ }
+ delete [] table;
+ table = 0;
+ }
}
-const HashEntry* Lookup::findEntry(const struct HashTable* table, const Identifier& s)
+void setUpStaticFunctionSlot(ExecState* exec, const HashEntry* entry, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
{
- return KJS::findEntry(table, s.ustring().rep()->computedHash(), s.data(), s.size());
-}
+ ASSERT(entry->attributes() & Function);
+ JSValue** location = thisObj->getDirectLocation(propertyName);
-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;
-}
+ if (!location) {
+ PrototypeFunction* function = new (exec) PrototypeFunction(exec, entry->functionLength(), propertyName, entry->function());
+ thisObj->putDirect(propertyName, function, entry->attributes());
+ location = thisObj->getDirectLocation(propertyName);
+ }
-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;
+ slot.setValueSlot(thisObj, location, thisObj->offsetForLocation(location));
}
-}
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/lookup.h b/JavaScriptCore/kjs/lookup.h
index 199c9d9..a547613 100644
--- a/JavaScriptCore/kjs/lookup.h
+++ b/JavaScriptCore/kjs/lookup.h
@@ -1,7 +1,6 @@
-// -*- c-basic-offset: 2 -*-
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2003, 2006, 2007 Apple Inc. All rights reserved.
+ * Copyright (C) 2003, 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
@@ -23,320 +22,217 @@
#define KJS_lookup_h
#include "ExecState.h"
-#include "function.h"
-#include "identifier.h"
+#include "JSFunction.h"
#include "JSGlobalObject.h"
-#include "object.h"
+#include "JSObject.h"
+#include "PropertySlot.h"
+#include "identifier.h"
#include <stdio.h>
#include <wtf/Assertions.h>
-namespace KJS {
+namespace JSC {
- /**
- * An entry in a hash table.
- */
- struct HashEntry {
- /**
- * s is the key (e.g. a property name)
- */
- const char* s;
+ // Hash table generated by the create_hash_table script.
+ struct HashTableValue {
+ const char* key; // property name
+ unsigned char attributes; // JSObject attributes
+ intptr_t value1;
+ intptr_t value2;
+ };
- /**
- * 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;
+ // FIXME: There is no reason this get function can't be simpler.
+ // ie. typedef JSValue* (*GetFunction)(ExecState*, JSObject* baseObject)
+ typedef PropertySlot::GetValueFunc GetFunction;
+ typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue* value);
+
+ class HashEntry {
+ public:
+ void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2)
+ {
+ m_key = key;
+ m_attributes = attributes;
+ m_u.store.value1 = v1;
+ m_u.store.value2 = v2;
+ }
+
+ void setKey(UString::Rep* key) { m_key = key; }
+ UString::Rep* key() const { return m_key; }
+
+ unsigned char attributes() const { return m_attributes; }
+
+ NativeFunction function() const { ASSERT(m_attributes & Function); return m_u.function.functionValue; }
+ unsigned char functionLength() const { ASSERT(m_attributes & Function); return static_cast<unsigned char>(m_u.function.length); }
+
+ GetFunction propertyGetter() const { ASSERT(!(m_attributes & Function)); return m_u.property.get; }
+ PutFunction propertyPutter() const { ASSERT(!(m_attributes & Function)); return m_u.property.put; }
+
+ intptr_t lexerValue() const { ASSERT(!m_attributes); return m_u.lexer.value; }
+
+ private:
+ UString::Rep* m_key;
+ unsigned char m_attributes; // JSObject attributes
+
+ union {
+ struct {
+ intptr_t value1;
+ intptr_t value2;
+ } store;
+ struct {
+ NativeFunction functionValue;
+ intptr_t length; // number of arguments for function
+ } function;
+ struct {
+ GetFunction get;
+ PutFunction put;
+ } property;
+ struct {
+ intptr_t value;
+ intptr_t unused;
+ } lexer;
+ } m_u;
+ };
+
+ struct HashTable {
+ int hashSizeMask; // Precomputed size for the hash table (minus 1).
+ const HashTableValue* values; // Fixed values generated by script.
+ mutable const HashEntry* table; // Table allocated at runtime.
+
+ ALWAYS_INLINE void initializeIfNeeded(JSGlobalData* globalData) const
+ {
+ if (!table)
+ createTable(globalData);
+ }
+
+ ALWAYS_INLINE void initializeIfNeeded(ExecState* exec) const
+ {
+ if (!table)
+ createTable(&exec->globalData());
+ }
+
+ void deleteTable() const;
+
+ // Find an entry in the table, and return the entry.
+ ALWAYS_INLINE const HashEntry* entry(JSGlobalData* globalData, const Identifier& identifier) const
+ {
+ initializeIfNeeded(globalData);
+ return entry(identifier);
+ }
+
+ ALWAYS_INLINE const HashEntry* entry(ExecState* exec, const Identifier& identifier) const
+ {
+ initializeIfNeeded(exec);
+ return entry(identifier);
+ }
+
+ private:
+ ALWAYS_INLINE const HashEntry* entry(const Identifier& identifier) const
+ {
+ ASSERT(table);
+ const HashEntry* entry = &table[identifier.ustring().rep()->computedHash() & hashSizeMask];
+ if (entry->key() != identifier.ustring().rep())
+ return 0;
+ return entry;
+ }
+
+ // Convert the hash table keys to identifiers.
+ void createTable(JSGlobalData*) const;
+ };
+
+ void setUpStaticFunctionSlot(ExecState*, const HashEntry*, JSObject* thisObject, const Identifier& propertyName, PropertySlot&);
/**
- * 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
+ * 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).
*/
- int size;
+ template <class ThisImp, class ParentImp>
+ inline bool getStaticPropertySlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ {
+ const HashEntry* entry = table->entry(exec, propertyName);
+
+ if (!entry) // not found, forward to parent
+ return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
+
+ if (entry->attributes() & Function)
+ setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+ else
+ slot.setCustom(thisObj, entry->propertyGetter());
+
+ return true;
+ }
+
/**
- * pointer to the array of entries
- * Mind that some entries in the array are null (0,0,0,0).
+ * Simplified version of getStaticPropertySlot in case there are only functions.
+ * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing
+ * a dummy getValueProperty.
*/
- const HashEntry* entries;
+ template <class ParentImp>
+ inline bool getStaticFunctionSlot(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ {
+ if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertySlot(exec, propertyName, slot))
+ return true;
+
+ const HashEntry* entry = table->entry(exec, propertyName);
+ if (!entry)
+ return false;
+
+ setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot);
+ return true;
+ }
+
/**
- * the maximum value for the hash minus 1. Always smaller than size.
+ * Simplified version of getStaticPropertySlot in case there are no functions, only "values".
+ * Using this instead of getStaticPropertySlot removes the need for a FuncImp class.
*/
- int hashSizeMask;
- };
-
- /**
- * @short Fast keyword lookup.
- */
- class Lookup {
- public:
+ template <class ThisImp, class ParentImp>
+ inline bool getStaticValueSlot(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertySlot& slot)
+ {
+ const HashEntry* entry = table->entry(exec, propertyName);
+
+ if (!entry) // not found, forward to parent
+ return thisObj->ParentImp::getOwnPropertySlot(exec, propertyName, slot);
+
+ ASSERT(!(entry->attributes() & Function));
+
+ slot.setCustom(thisObj, entry->propertyGetter());
+ return true;
+ }
+
/**
- * Find an entry in the table, and return its value (i.e. the value field of HashEntry)
+ * 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.
*/
- static int find(const struct HashTable*, const Identifier&);
- static int find(const struct HashTable*, const UChar*, unsigned int len);
+ template <class ThisImp>
+ inline bool lookupPut(ExecState* exec, const Identifier& propertyName, JSValue* value, const HashTable* table, ThisImp* thisObj)
+ {
+ const HashEntry* entry = table->entry(exec, propertyName);
+
+ if (!entry)
+ return false;
+
+ if (entry->attributes() & Function) // function: put as override property
+ thisObj->putDirect(propertyName, value);
+ else if (!(entry->attributes() & ReadOnly))
+ entry->propertyPutter()(exec, thisObj, value);
+
+ return true;
+ }
/**
- * 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.
+ * 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.
*/
- 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, int attr,
- 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->JSObject::put(exec, propertyName, value, attr);
- else if (!(entry->attr & ReadOnly))
- thisObj->putValueProperty(exec, entry->value.intValue, value, attr);
-
- 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, int attr,
- const HashTable* table, ThisImp* thisObj)
- {
- if (!lookupPut<ThisImp>(exec, propertyName, value, attr, table, thisObj))
- thisObj->ParentImp::put(exec, propertyName, value, attr); // 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);
+ template <class ThisImp, class ParentImp>
+ inline void lookupPut(ExecState* exec, const Identifier& propertyName, JSValue* value, const HashTable* table, ThisImp* thisObj, PutPropertySlot& slot)
+ {
+ if (!lookupPut<ThisImp>(exec, propertyName, value, table, thisObj))
+ thisObj->ParentImp::put(exec, propertyName, value, slot); // not found: forward to parent
}
- JSObject* newObject = new ClassCtor(exec);
- globalObject->putDirect(propertyName, newObject, Internal | 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); \
- }
+} // namespace JSC
#endif // KJS_lookup_h
diff --git a/JavaScriptCore/kjs/math_object.cpp b/JavaScriptCore/kjs/math_object.cpp
deleted file mode 100644
index 805efda..0000000
--- a/JavaScriptCore/kjs/math_object.cpp
+++ /dev/null
@@ -1,243 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 72e442f..0000000
--- a/JavaScriptCore/kjs/math_object.h
+++ /dev/null
@@ -1,65 +0,0 @@
-// -*- 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
index 94ef47d..b4aeb28 100644
--- a/JavaScriptCore/kjs/nodes.cpp
+++ b/JavaScriptCore/kjs/nodes.cpp
@@ -26,235 +26,127 @@
#include "config.h"
#include "nodes.h"
+#include "CodeGenerator.h"
#include "ExecState.h"
#include "JSGlobalObject.h"
+#include "JSStaticScopeObject.h"
+#include "LabelScope.h"
#include "Parser.h"
#include "PropertyNameArray.h"
-#include "array_object.h"
-#include "debugger.h"
-#include "function_object.h"
+#include "RegExpObject.h"
+#include "SamplingTool.h"
+#include "Debugger.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>
+#include <wtf/RefCountedLeakCounter.h>
+#include <wtf/Threading.h>
-namespace KJS {
+using namespace WTF;
-class FunctionBodyNodeWithDebuggerHooks : public FunctionBodyNode {
-public:
- FunctionBodyNodeWithDebuggerHooks(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
- virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
-};
-
-#define KJS_CHECKEXCEPTION \
-if (exec->hadException()) \
- return rethrowException(exec);
-
-#define KJS_CHECKEXCEPTIONVALUE \
-if (exec->hadException()) { \
- handleException(exec); \
- return jsUndefined(); \
-}
-
-#define KJS_CHECKEXCEPTIONNUMBER \
-if (exec->hadException()) { \
- handleException(exec); \
- return 0; \
-}
-
-#define KJS_CHECKEXCEPTIONBOOLEAN \
-if (exec->hadException()) { \
- handleException(exec); \
- return false; \
-}
-
-#define KJS_CHECKEXCEPTIONVOID \
-if (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;
-}
+namespace JSC {
// ------------------------------ Node -----------------------------------------
#ifndef NDEBUG
-#ifndef LOG_CHANNEL_PREFIX
-#define LOG_CHANNEL_PREFIX Log
+static RefCountedLeakCounter parserRefCountedCounter("JSC::Node");
#endif
-static WTFLogChannel LogKJSNodeLeaks = { 0x00000000, "", WTFLogChannelOn };
-
-struct ParserRefCountedCounter {
- static unsigned count;
- ParserRefCountedCounter()
- {
- if (count)
-#ifdef ANDROID // FIXME HACK : LOG not defined appropriately here
- ASSERT("LEAK: KJS::Node");
-#else
- LOG(KJSNodeLeaks, "LEAK: %u KJS::Node\n", count);
-#endif
- }
-};
-unsigned ParserRefCountedCounter::count = 0;
-static ParserRefCountedCounter parserRefCountedCounter;
-#endif
-
-static HashSet<ParserRefCounted*>* newTrackedObjects;
-static HashCountedSet<ParserRefCounted*>* trackedObjectExtraRefCounts;
-ParserRefCounted::ParserRefCounted()
+ParserRefCounted::ParserRefCounted(JSGlobalData* globalData)
+ : m_globalData(globalData)
{
#ifndef NDEBUG
- ++ParserRefCountedCounter::count;
+ parserRefCountedCounter.increment();
#endif
- if (!newTrackedObjects)
- newTrackedObjects = new HashSet<ParserRefCounted*>;
- newTrackedObjects->add(this);
- ASSERT(newTrackedObjects->contains(this));
+ if (!m_globalData->newParserObjects)
+ m_globalData->newParserObjects = new HashSet<ParserRefCounted*>;
+ m_globalData->newParserObjects->add(this);
+ ASSERT(m_globalData->newParserObjects->contains(this));
}
ParserRefCounted::~ParserRefCounted()
{
#ifndef NDEBUG
- --ParserRefCountedCounter::count;
+ parserRefCountedCounter.decrement();
#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));
+ if (m_globalData->newParserObjects) {
+ HashSet<ParserRefCounted*>::iterator it = m_globalData->newParserObjects->find(this);
+ if (it != m_globalData->newParserObjects->end()) {
+ m_globalData->newParserObjects->remove(it);
+ ASSERT(!m_globalData->parserObjectExtraRefCounts || !m_globalData->parserObjectExtraRefCounts->contains(this));
return;
}
}
- ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
+ ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this));
- if (!trackedObjectExtraRefCounts)
- trackedObjectExtraRefCounts = new HashCountedSet<ParserRefCounted*>;
- trackedObjectExtraRefCounts->add(this);
+ if (!m_globalData->parserObjectExtraRefCounts)
+ m_globalData->parserObjectExtraRefCounts = new HashCountedSet<ParserRefCounted*>;
+ m_globalData->parserObjectExtraRefCounts->add(this);
}
void ParserRefCounted::deref()
{
- ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
+ ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this));
- if (!trackedObjectExtraRefCounts) {
+ if (!m_globalData->parserObjectExtraRefCounts) {
delete this;
return;
}
- HashCountedSet<ParserRefCounted*>::iterator it = trackedObjectExtraRefCounts->find(this);
- if (it == trackedObjectExtraRefCounts->end())
+ HashCountedSet<ParserRefCounted*>::iterator it = m_globalData->parserObjectExtraRefCounts->find(this);
+ if (it == m_globalData->parserObjectExtraRefCounts->end())
delete this;
else
- trackedObjectExtraRefCounts->remove(it);
+ m_globalData->parserObjectExtraRefCounts->remove(it);
}
-unsigned ParserRefCounted::refcount()
+bool ParserRefCounted::hasOneRef()
{
- if (newTrackedObjects && newTrackedObjects->contains(this)) {
- ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(this));
- return 0;
+ if (m_globalData->newParserObjects && m_globalData->newParserObjects->contains(this)) {
+ ASSERT(!m_globalData->parserObjectExtraRefCounts || !m_globalData->parserObjectExtraRefCounts->contains(this));
+ return false;
}
- ASSERT(!newTrackedObjects || !newTrackedObjects->contains(this));
+ ASSERT(!m_globalData->newParserObjects || !m_globalData->newParserObjects->contains(this));
- if (!trackedObjectExtraRefCounts)
- return 1;
+ if (!m_globalData->parserObjectExtraRefCounts)
+ return true;
- return 1 + trackedObjectExtraRefCounts->count(this);
+ return !m_globalData->parserObjectExtraRefCounts->contains(this);
}
-void ParserRefCounted::deleteNewObjects()
+void ParserRefCounted::deleteNewObjects(JSGlobalData* globalData)
{
- if (!newTrackedObjects)
+ if (!globalData->newParserObjects)
return;
#ifndef NDEBUG
- HashSet<ParserRefCounted*>::iterator end = newTrackedObjects->end();
- for (HashSet<ParserRefCounted*>::iterator it = newTrackedObjects->begin(); it != end; ++it)
- ASSERT(!trackedObjectExtraRefCounts || !trackedObjectExtraRefCounts->contains(*it));
+ HashSet<ParserRefCounted*>::iterator end = globalData->newParserObjects->end();
+ for (HashSet<ParserRefCounted*>::iterator it = globalData->newParserObjects->begin(); it != end; ++it)
+ ASSERT(!globalData->parserObjectExtraRefCounts || !globalData->parserObjectExtraRefCounts->contains(*it));
#endif
- deleteAllValues(*newTrackedObjects);
- delete newTrackedObjects;
- newTrackedObjects = 0;
-}
-
-Node::Node()
- : m_expectedReturnType(ObjectType)
-{
- m_line = lexer().lineNo();
+ deleteAllValues(*globalData->newParserObjects);
+ delete globalData->newParserObjects;
+ globalData->newParserObjects = 0;
}
-Node::Node(JSType expectedReturn)
- : m_expectedReturnType(expectedReturn)
+Node::Node(JSGlobalData* globalData)
+ : ParserRefCounted(globalData)
{
- m_line = lexer().lineNo();
+ m_line = globalData->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) JSC_FAST_CALL;
static void substitute(UString& string, const UString& substring)
{
int position = string.find("%s");
@@ -265,124 +157,30 @@ static void substitute(UString& string, const UString& substring)
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)
+RegisterID* ThrowableExpressionData::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg)
{
- 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));
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), msg));
+ generator.emitThrow(exception);
+ return exception;
}
-JSValue* Node::throwError(ExecState* exec, ErrorType e, const char* msg, JSValue* v, Node* expr, const Identifier& label)
+RegisterID* ThrowableExpressionData::emitThrowError(CodeGenerator& generator, ErrorType e, const char* msg, 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)) {
- bool cont = dbg->exception(exec, currentSourceId(exec), m_line, exceptionValue);
- if (!cont)
- dbg->imp()->abort();
- }
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), message));
+ generator.emitThrow(exception);
+ return exception;
}
-
-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)
+StatementNode::StatementNode(JSGlobalData* globalData)
+ : Node(globalData)
+ , m_lastLine(-1)
{
- m_line = -1;
}
void StatementNode::setLoc(int firstLine, int lastLine)
@@ -398,3535 +196,1077 @@ 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());
+ m_statements.append(statement);
}
// ------------------------------ NullNode -------------------------------------
-JSValue* NullNode::evaluate(ExecState* )
-{
- return jsNull();
-}
-
-// ------------------------------ FalseNode ----------------------------------
-
-JSValue* FalseNode::evaluate(ExecState*)
+RegisterID* NullNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- return jsBoolean(false);
+ if (dst == ignoredResult())
+ return 0;
+ return generator.emitLoad(dst, jsNull());
}
-// ------------------------------ TrueNode ----------------------------------
+// ------------------------------ BooleanNode ----------------------------------
-JSValue* TrueNode::evaluate(ExecState*)
+RegisterID* BooleanNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- return jsBoolean(true);
+ if (dst == ignoredResult())
+ return 0;
+ return generator.emitLoad(dst, m_value);
}
// ------------------------------ 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*)
+RegisterID* NumberNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- uint32_t i;
- if (JSImmediate::getTruncatedUInt32(m_value, i))
- return i;
- bool ok;
- return JSValue::toUInt32SlowCase(m_double, ok);
+ if (dst == ignoredResult())
+ return 0;
+ return generator.emitLoad(dst, m_double);
}
// ------------------------------ StringNode -----------------------------------
-JSValue* StringNode::evaluate(ExecState*)
-{
- return jsOwnedString(m_value);
-}
-
-double StringNode::evaluateToNumber(ExecState*)
-{
- return m_value.toDouble();
-}
-
-bool StringNode::evaluateToBoolean(ExecState*)
+RegisterID* StringNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- return !m_value.isEmpty();
+ if (dst == ignoredResult())
+ return 0;
+ return generator.emitLoad(dst, m_value);
}
// ------------------------------ RegExpNode -----------------------------------
-JSValue* RegExpNode::evaluate(ExecState* exec)
+RegisterID* RegExpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- return exec->lexicalGlobalObject()->regExpConstructor()->createRegExpImp(exec, m_regExp);
+ RefPtr<RegExp> regExp = RegExp::create(generator.globalData(), m_pattern, m_flags);
+ if (!regExp->isValid())
+ return emitThrowError(generator, SyntaxError, ("Invalid regular expression: " + UString(regExp->errorMessage())).UTF8String().c_str());
+ if (dst == ignoredResult())
+ return 0;
+ return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get());
}
// ------------------------------ ThisNode -------------------------------------
-// ECMA 11.1.1
-JSValue* ThisNode::evaluate(ExecState* exec)
+RegisterID* ThisNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- return exec->thisValue();
+ if (dst == ignoredResult())
+ return 0;
+ return generator.moveToDestinationIfNeeded(dst, generator.thisRegister());
}
// ------------------------------ 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)
+bool ResolveNode::isPure(CodeGenerator& generator) const
{
- JSValue* v = inlineEvaluate(exec);
- KJS_CHECKEXCEPTIONNUMBER
- return v->toNumber(exec);
+ return generator.isLocal(m_ident);
}
-bool ResolveNode::evaluateToBoolean(ExecState* exec)
+RegisterID* ResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ if (RegisterID* local = generator.registerFor(m_ident)) {
+ if (dst == ignoredResult())
+ return 0;
+ return generator.moveToDestinationIfNeeded(dst, local);
+ }
+
+ generator.emitExpressionInfo(m_startOffset + m_ident.size(), m_ident.size(), 0);
+ return generator.emitResolve(generator.finalDestination(dst), m_ident);
}
-// ------------------------------ ElementNode ----------------------------------
+// ------------------------------ ArrayNode ------------------------------------
-void ElementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* ArrayNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- if (m_next)
- nodeStack.append(m_next.get());
- ASSERT(m_node);
- nodeStack.append(m_node.get());
-}
+ // FIXME: Should we put all of this code into emitNewArray?
-// 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);
+ unsigned length = 0;
+ ElementNode* firstPutElement;
+ for (firstPutElement = m_element.get(); firstPutElement; firstPutElement = firstPutElement->next()) {
+ if (firstPutElement->elision())
+ break;
+ ++length;
}
- return array;
-}
-// ------------------------------ ArrayNode ------------------------------------
+ if (!firstPutElement && !m_elision)
+ return generator.emitNewArray(generator.finalDestination(dst), m_element.get());
-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;
+ RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element.get());
- 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;
+ for (ElementNode* n = firstPutElement; n; n = n->next()) {
+ RegisterID* value = generator.emitNode(n->value());
+ length += n->elision();
+ generator.emitPutByIndex(array.get(), length++, value);
}
- if (m_optional)
- array->put(exec, exec->propertyNames().length, jsNumber(m_elision + length));
+ if (m_elision) {
+ RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length));
+ generator.emitPutById(array.get(), generator.propertyNames().length, value);
+ }
- return array;
+ return generator.moveToDestinationIfNeeded(dst, array.get());
}
// ------------------------------ ObjectLiteralNode ----------------------------
-void ObjectLiteralNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* ObjectLiteralNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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());
+ if (!m_list) {
+ if (dst == ignoredResult())
+ return 0;
+ return generator.emitNewObject(generator.finalDestination(dst));
+ }
+ return generator.emitNode(dst, m_list.get());
}
// ------------------------------ 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)
+RegisterID* PropertyListNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSObject* obj = exec->lexicalGlobalObject()->objectConstructor()->construct(exec, exec->emptyList());
-
+ RefPtr<RegisterID> newObj = generator.tempDestination(dst);
+
+ generator.emitNewObject(newObj.get());
+
for (PropertyListNode* p = this; p; p = p->m_next.get()) {
- JSValue* v = p->m_node->m_assign->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
-
+ RegisterID* value = generator.emitNode(p->m_node->m_assign.get());
+
switch (p->m_node->m_type) {
- case PropertyNode::Getter:
- ASSERT(v->isObject());
- obj->defineGetter(exec, p->m_node->name(), static_cast<JSObject* >(v));
+ case PropertyNode::Constant: {
+ generator.emitPutById(newObj.get(), p->m_node->name(), value);
break;
- case PropertyNode::Setter:
- ASSERT(v->isObject());
- obj->defineSetter(exec, p->m_node->name(), static_cast<JSObject* >(v));
+ }
+ case PropertyNode::Getter: {
+ generator.emitPutGetter(newObj.get(), p->m_node->name(), value);
break;
- case PropertyNode::Constant:
- obj->put(exec, p->m_node->name(), v);
+ }
+ case PropertyNode::Setter: {
+ generator.emitPutSetter(newObj.get(), p->m_node->name(), value);
break;
+ }
+ default:
+ ASSERT_NOT_REACHED();
}
}
-
- 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();
+
+ return generator.moveToDestinationIfNeeded(dst, newObj.get());
}
// ------------------------------ 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)
+RegisterID* BracketAccessorNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments, m_subscript->isPure(generator));
+ RegisterID* property = generator.emitNode(m_subscript.get());
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property);
}
// ------------------------------ 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)
+RegisterID* DotAccessorNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* v = inlineEvaluate(exec);
- KJS_CHECKEXCEPTIONNUMBER
- return v->toUInt32(exec);
+ RegisterID* base = generator.emitNode(m_base.get());
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ return generator.emitGetById(generator.finalDestination(dst), base, m_ident);
}
// ------------------------------ ArgumentListNode -----------------------------
-void ArgumentListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* ArgumentListNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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());
+ return generator.emitNode(dst, m_expr.get());
}
// ------------------------------ NewExprNode ----------------------------------
-void NewExprNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* NewExprNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- if (m_args)
- nodeStack.append(m_args.get());
- nodeStack.append(m_expr.get());
+ RefPtr<RegisterID> func = generator.emitNode(m_expr.get());
+ return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
}
-// ECMA 11.2.2
-
-JSValue* NewExprNode::inlineEvaluate(ExecState* exec)
+RegisterID* EvalFunctionCallNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ RefPtr<RegisterID> base = generator.tempDestination(dst);
+ RefPtr<RegisterID> func = generator.newTemporary();
+ generator.emitResolveWithBase(base.get(), func.get(), generator.propertyNames().eval);
+ return generator.emitCallEval(generator.finalDestination(dst, base.get()), func.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
}
-JSValue* NewExprNode::evaluate(ExecState* exec)
+RegisterID* FunctionCallValueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- return inlineEvaluate(exec);
+ RefPtr<RegisterID> func = generator.emitNode(m_expr.get());
+ return generator.emitCall(generator.finalDestination(dst), func.get(), 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
}
-double NewExprNode::evaluateToNumber(ExecState* exec)
+RegisterID* FunctionCallResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* v = inlineEvaluate(exec);
- KJS_CHECKEXCEPTIONNUMBER
- return v->toNumber(exec);
-}
+ if (RefPtr<RegisterID> local = generator.registerFor(m_ident))
+ return generator.emitCall(generator.finalDestination(dst), local.get(), 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
-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());
+ int index = 0;
+ size_t depth = 0;
+ JSObject* globalObject = 0;
+ if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) {
+ RefPtr<RegisterID> func = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject);
+ return generator.emitCall(generator.finalDestination(dst), func.get(), 0, m_args.get(), m_divot, m_startOffset, m_endOffset);
}
- 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);
+ RefPtr<RegisterID> base = generator.tempDestination(dst);
+ RefPtr<RegisterID> func = generator.newTemporary();
+ int identifierStart = m_divot - m_startOffset;
+ generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0);
+ generator.emitResolveFunction(base.get(), func.get(), m_ident);
+ return generator.emitCall(generator.finalDestination(dst, base.get()), func.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
}
-int32_t FunctionCallDotNode::evaluateToInt32(ExecState* exec)
+RegisterID* FunctionCallBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* v = inlineEvaluate(exec);
- KJS_CHECKEXCEPTIONNUMBER
- return v->toInt32(exec);
+ RefPtr<RegisterID> base = generator.emitNode(m_base.get());
+ RegisterID* property = generator.emitNode(m_subscript.get());
+ generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
+ RefPtr<RegisterID> function = generator.emitGetByVal(generator.newTemporary(), base.get(), property);
+ return generator.emitCall(generator.finalDestination(dst, base.get()), function.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
}
-uint32_t FunctionCallDotNode::evaluateToUInt32(ExecState* exec)
+RegisterID* FunctionCallDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* v = inlineEvaluate(exec);
- KJS_CHECKEXCEPTIONNUMBER
- return v->toUInt32(exec);
+ RefPtr<RegisterID> base = generator.emitNode(m_base.get());
+ generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
+ RefPtr<RegisterID> function = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
+ return generator.emitCall(generator.finalDestination(dst, base.get()), function.get(), base.get(), m_args.get(), m_divot, m_startOffset, m_endOffset);
}
-// 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)
+static RegisterID* emitPreIncOrDec(CodeGenerator& generator, RegisterID* srcDst, Operator oper)
{
- // 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);
+ return (oper == OpPlusPlus) ? generator.emitPreInc(srcDst) : generator.emitPreDec(srcDst);
}
-void PostIncResolveNode::optimizeForUnnecessaryResult()
+static RegisterID* emitPostIncOrDec(CodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper)
{
- new (this) PreIncResolveNode(PlacementNewAdopt);
+ return (oper == OpPlusPlus) ? generator.emitPostInc(dst, srcDst) : generator.emitPostDec(dst, srcDst);
}
-JSValue* PostIncLocalVarNode::evaluate(ExecState* exec)
+RegisterID* PostfixResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
-}
+ if (RegisterID* local = generator.registerFor(m_ident)) {
+ if (generator.isLocalConstant(m_ident)) {
+ if (dst == ignoredResult())
+ return 0;
+ return generator.emitToJSNumber(generator.finalDestination(dst), local);
+ }
-// 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);
+ if (dst == ignoredResult())
+ return emitPreIncOrDec(generator, local, m_operator);
+ return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator);
}
-}
-
-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;
+ int index = 0;
+ size_t depth = 0;
+ JSObject* globalObject = 0;
+ if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) {
+ RefPtr<RegisterID> value = generator.emitGetScopedVar(generator.newTemporary(), depth, index, globalObject);
+ RegisterID* oldValue;
+ if (dst == ignoredResult()) {
+ oldValue = 0;
+ emitPreIncOrDec(generator, value.get(), m_operator);
+ } else {
+ oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
}
+ generator.emitPutScopedVar(depth, index, value.get(), globalObject);
+ return oldValue;
+ }
- ++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);
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ RefPtr<RegisterID> value = generator.newTemporary();
+ RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident);
+ RegisterID* oldValue;
+ if (dst == ignoredResult()) {
+ oldValue = 0;
+ emitPreIncOrDec(generator, value.get(), m_operator);
+ } else {
+ oldValue = emitPostIncOrDec(generator, generator.finalDestination(dst), value.get(), m_operator);
+ }
+ generator.emitPutById(base.get(), m_ident, value.get());
+ return oldValue;
}
// ------------------------------ 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)
+RegisterID* PostfixBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* baseValue = m_base->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
- JSValue* subscript = m_subscript->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
-
- JSObject* base = baseValue->toObject(exec);
+ RefPtr<RegisterID> base = generator.emitNode(m_base.get());
+ RefPtr<RegisterID> property = generator.emitNode(m_subscript.get());
- 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;
+ generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
+ RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get());
+ RegisterID* oldValue;
+ if (dst == ignoredResult()) {
+ oldValue = 0;
+ if (m_operator == OpPlusPlus)
+ generator.emitPreInc(value.get());
+ else
+ generator.emitPreDec(value.get());
+ } else {
+ oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get());
}
-
- 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;
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ generator.emitPutByVal(base.get(), property.get(), value.get());
+ return oldValue;
}
// ------------------------------ 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)
+RegisterID* PostfixDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* baseValue = m_base->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
- JSObject* base = baseValue->toObject(exec);
+ RefPtr<RegisterID> base = generator.emitNode(m_base.get());
- 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;
+ generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
+ RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident);
+ RegisterID* oldValue;
+ if (dst == ignoredResult()) {
+ oldValue = 0;
+ if (m_operator == OpPlusPlus)
+ generator.emitPreInc(value.get());
+ else
+ generator.emitPreDec(value.get());
+ } else {
+ oldValue = (m_operator == OpPlusPlus) ? generator.emitPostInc(generator.finalDestination(dst), value.get()) : generator.emitPostDec(generator.finalDestination(dst), value.get());
+ }
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ generator.emitPutById(base.get(), m_ident, value.get());
+ return oldValue;
}
// ------------------------------ PostfixErrorNode -----------------------------------
-JSValue* PostfixErrorNode::evaluate(ExecState* exec)
+RegisterID* PostfixErrorNode::emitCode(CodeGenerator& generator, RegisterID*)
{
- throwError(exec, ReferenceError, "Postfix %s operator applied to value that is not a reference.",
- m_operator == OpPlusPlus ? "++" : "--");
- handleException(exec);
- return jsUndefined();
+ return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Postfix ++ operator applied to value that is not a reference." : "Postfix -- operator applied to value that is not a reference.");
}
// ------------------------------ 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)
+RegisterID* DeleteResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- // 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);
-}
+ if (generator.registerFor(m_ident))
+ return generator.emitUnexpectedLoad(generator.finalDestination(dst), false);
-JSValue* LocalVarDeleteNode::evaluate(ExecState*)
-{
- return jsBoolean(false);
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident);
+ return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident);
}
// ------------------------------ 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)
+RegisterID* DeleteBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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));
+ RefPtr<RegisterID> r0 = generator.emitNode(m_base.get());
+ RegisterID* r1 = generator.emitNode(m_subscript.get());
- Identifier propertyName(subscript->toString(exec));
- return jsBoolean(base->deleteProperty(exec, propertyName));
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1);
}
// ------------------------------ DeleteDotNode -----------------------------------
-void DeleteDotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* DeleteDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- nodeStack.append(m_base.get());
-}
-
-JSValue* DeleteDotNode::evaluate(ExecState* exec)
-{
- JSValue* baseValue = m_base->evaluate(exec);
- JSObject* base = baseValue->toObject(exec);
- KJS_CHECKEXCEPTIONVALUE
+ RegisterID* r0 = generator.emitNode(m_base.get());
- return jsBoolean(base->deleteProperty(exec, m_ident));
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident);
}
// ------------------------------ DeleteValueNode -----------------------------------
-void DeleteValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
-{
- nodeStack.append(m_expr.get());
-}
-
-JSValue* DeleteValueNode::evaluate(ExecState* exec)
+RegisterID* DeleteValueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- m_expr->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
+ generator.emitNode(ignoredResult(), m_expr.get());
// delete on a non-location expression ignores the value and returns true
- return jsBoolean(true);
+ return generator.emitUnexpectedLoad(generator.finalDestination(dst), true);
}
// ------------------------------ VoidNode -------------------------------------
-void VoidNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* VoidNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- nodeStack.append(m_expr.get());
-}
-
-// ECMA 11.4.2
-JSValue* VoidNode::evaluate(ExecState* exec)
-{
- m_expr->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
-
- return jsUndefined();
+ if (dst == ignoredResult()) {
+ generator.emitNode(ignoredResult(), m_expr.get());
+ return 0;
+ }
+ RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get());
+ return generator.emitLoad(dst, jsUndefined());
}
-// ECMA 11.4.3
-
// ------------------------------ TypeOfValueNode -----------------------------------
-void TypeOfValueNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* TypeOfResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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");
+ if (RegisterID* local = generator.registerFor(m_ident)) {
+ if (dst == ignoredResult())
+ return 0;
+ return generator.emitTypeOf(generator.finalDestination(dst), local);
}
-}
-
-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");
+ RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident);
+ generator.emitGetById(scratch.get(), scratch.get(), m_ident);
+ if (dst == ignoredResult())
+ return 0;
+ return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get());
}
// ------------------------------ TypeOfValueNode -----------------------------------
-JSValue* TypeOfValueNode::evaluate(ExecState* exec)
+RegisterID* TypeOfValueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ if (dst == ignoredResult()) {
+ generator.emitNode(ignoredResult(), m_expr.get());
+ return 0;
}
+ RefPtr<RegisterID> src = generator.emitNode(m_expr.get());
+ return generator.emitTypeOf(generator.finalDestination(dst), src.get());
}
-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;
-}
+// ------------------------------ PrefixResolveNode ----------------------------------
-JSValue* PreIncResolveNode::evaluate(ExecState* exec)
+RegisterID* PrefixResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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;
+ if (RegisterID* local = generator.registerFor(m_ident)) {
+ if (generator.isLocalConstant(m_ident)) {
+ if (dst == ignoredResult())
+ return 0;
+ RefPtr<RegisterID> r0 = generator.emitUnexpectedLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0);
+ return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes());
}
- ++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);
+ emitPreIncOrDec(generator, local, m_operator);
+ return generator.moveToDestinationIfNeeded(dst, local);
}
-}
-
-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 ----------------------------------
+ int index = 0;
+ size_t depth = 0;
+ JSObject* globalObject = 0;
+ if (generator.findScopedProperty(m_ident, index, depth, false, globalObject) && index != missingSymbolMarker()) {
+ RefPtr<RegisterID> propDst = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject);
+ emitPreIncOrDec(generator, propDst.get(), m_operator);
+ generator.emitPutScopedVar(depth, index, propDst.get(), globalObject);
+ return generator.moveToDestinationIfNeeded(dst, propDst.get());
+ }
-JSValue* PostDecConstNode::evaluate(ExecState* exec)
-{
- ASSERT(exec->variableObject() == exec->scopeChain().top());
- return jsNumber(exec->localStorage()[m_index].value->toNumber(exec));
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ RefPtr<RegisterID> propDst = generator.tempDestination(dst);
+ RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), propDst.get(), m_ident);
+ emitPreIncOrDec(generator, propDst.get(), m_operator);
+ generator.emitPutById(base.get(), m_ident, propDst.get());
+ return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
// ------------------------------ 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)
+RegisterID* PrefixBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ RefPtr<RegisterID> base = generator.emitNode(m_base.get());
+ RefPtr<RegisterID> property = generator.emitNode(m_subscript.get());
+ RefPtr<RegisterID> propDst = generator.tempDestination(dst);
- 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;
+ generator.emitExpressionInfo(m_divot + m_subexpressionDivotOffset, m_subexpressionStartOffset, m_endOffset - m_subexpressionDivotOffset);
+ RegisterID* value = generator.emitGetByVal(propDst.get(), base.get(), property.get());
+ if (m_operator == OpPlusPlus)
+ generator.emitPreInc(value);
+ else
+ generator.emitPreDec(value);
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ generator.emitPutByVal(base.get(), property.get(), value);
+ return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
// ------------------------------ 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)
+RegisterID* PrefixDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ RefPtr<RegisterID> base = generator.emitNode(m_base.get());
+ RefPtr<RegisterID> propDst = generator.tempDestination(dst);
- return n2;
+ generator.emitExpressionInfo(m_divot + m_subexpressionDivotOffset, m_subexpressionStartOffset, m_endOffset - m_subexpressionDivotOffset);
+ RegisterID* value = generator.emitGetById(propDst.get(), base.get(), m_ident);
+ if (m_operator == OpPlusPlus)
+ generator.emitPreInc(value);
+ else
+ generator.emitPreDec(value);
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ generator.emitPutById(base.get(), m_ident, value);
+ return generator.moveToDestinationIfNeeded(dst, propDst.get());
}
// ------------------------------ 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)
+RegisterID* PrefixErrorNode::emitCode(CodeGenerator& generator, RegisterID*)
{
- return m_expr->evaluateToNumber(exec);
+ return emitThrowError(generator, ReferenceError, m_operator == OpPlusPlus ? "Prefix ++ operator applied to value that is not a reference." : "Prefix -- operator applied to value that is not a reference.");
}
-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));
-}
+// ------------------------------ Unary Operation Nodes -----------------------------------
-double NegateNode::evaluateToNumber(ExecState* exec)
+RegisterID* UnaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- // No need to check exception, caller will do so right after evaluateToNumber()
- return -m_expr->evaluateToNumber(exec);
+ RegisterID* src = generator.emitNode(m_expr.get());
+ return generator.emitUnaryOp(opcode(), generator.finalDestination(dst), src, m_expr->resultDescriptor());
}
-// ------------------------------ BitwiseNotNode -------------------------------
+// ------------------------------ Binary Operation Nodes -----------------------------------
-void BitwiseNotNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* BinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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;
+ OpcodeID opcode = this->opcode();
+ if (opcode == op_neq) {
+ if (m_expr1->isNull() || m_expr2->isNull()) {
+ RefPtr<RegisterID> src = generator.emitNode(dst, m_expr1->isNull() ? m_expr2.get() : m_expr1.get());
+ return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get(), ResultType::unknown());
+ }
}
- 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());
+ RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
+ RegisterID* src2 = generator.emitNode(m_expr2.get());
+ return generator.emitBinaryOp(opcode, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor()));
}
-// ECMA 11.8.7
-JSValue* InNode::evaluate(ExecState* exec)
+RegisterID* EqualNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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;
+ if (m_expr1->isNull() || m_expr2->isNull()) {
+ RefPtr<RegisterID> src = generator.emitNode(dst, m_expr1->isNull() ? m_expr2.get() : m_expr1.get());
+ return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get(), ResultType::unknown());
}
- 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);
+ RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
+ RegisterID* src2 = generator.emitNode(m_expr2.get());
+ return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2);
}
-JSValue* EqualNode::evaluate(ExecState* exec)
+RegisterID* StrictEqualNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- return jsBoolean(inlineEvaluateToBoolean(exec));
+ RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
+ RegisterID* src2 = generator.emitNode(m_expr2.get());
+ return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2);
}
-bool EqualNode::evaluateToBoolean(ExecState* exec)
+RegisterID* ReverseBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- return inlineEvaluateToBoolean(exec);
+ RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
+ RegisterID* src2 = generator.emitNode(m_expr2.get());
+ return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src2, src1.get(), OperandTypes(m_expr2->resultDescriptor(), m_expr1->resultDescriptor()));
}
-void NotEqualNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* ThrowableBinaryOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- nodeStack.append(m_expr2.get());
- nodeStack.append(m_expr1.get());
+ RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
+ RegisterID* src2 = generator.emitNode(m_expr2.get());
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ return generator.emitBinaryOp(opcode(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor()));
}
-// ECMA 11.9.2
-bool NotEqualNode::inlineEvaluateToBoolean(ExecState* exec)
+RegisterID* InstanceOfNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* v1 = m_expr1->evaluate(exec);
- KJS_CHECKEXCEPTIONBOOLEAN
- JSValue* v2 = m_expr2->evaluate(exec);
- KJS_CHECKEXCEPTIONBOOLEAN
+ RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1.get(), m_rightHasAssignments, m_expr2->isPure(generator));
+ RefPtr<RegisterID> src2 = generator.emitNode(m_expr2.get());
- 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
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype);
- 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);
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype);
}
// ------------------------------ 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)
+RegisterID* LogicalOpNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* v1 = m_expr1->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
- if (v1->toBoolean(exec))
- return v1;
- return m_expr2->evaluate(exec);
-}
+ RefPtr<RegisterID> temp = generator.tempDestination(dst);
+ RefPtr<LabelID> target = generator.newLabel();
+
+ generator.emitNode(temp.get(), m_expr1.get());
+ if (m_operator == OpLogicalAnd)
+ generator.emitJumpIfFalse(temp.get(), target.get());
+ else
+ generator.emitJumpIfTrue(temp.get(), target.get());
+ generator.emitNode(temp.get(), m_expr2.get());
+ generator.emitLabel(target.get());
-bool LogicalOrNode::evaluateToBoolean(ExecState* exec)
-{
- bool b = m_expr1->evaluateToBoolean(exec);
- KJS_CHECKEXCEPTIONBOOLEAN
- return b || m_expr2->evaluateToBoolean(exec);
+ return generator.moveToDestinationIfNeeded(dst, temp.get());
}
// ------------------------------ ConditionalNode ------------------------------
-void ConditionalNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* ConditionalNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- nodeStack.append(m_expr2.get());
- nodeStack.append(m_expr1.get());
- nodeStack.append(m_logical.get());
-}
+ RefPtr<RegisterID> newDst = generator.finalDestination(dst);
+ RefPtr<LabelID> beforeElse = generator.newLabel();
+ RefPtr<LabelID> afterElse = generator.newLabel();
-// 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);
-}
+ RegisterID* cond = generator.emitNode(m_logical.get());
+ generator.emitJumpIfFalse(cond, beforeElse.get());
-bool ConditionalNode::evaluateToBoolean(ExecState* exec)
-{
- bool b = m_logical->evaluateToBoolean(exec);
- KJS_CHECKEXCEPTIONBOOLEAN
- return b ? m_expr1->evaluateToBoolean(exec) : m_expr2->evaluateToBoolean(exec);
-}
+ generator.emitNode(newDst.get(), m_expr1.get());
+ generator.emitJump(afterElse.get());
-double ConditionalNode::evaluateToNumber(ExecState* exec)
-{
- bool b = m_logical->evaluateToBoolean(exec);
- KJS_CHECKEXCEPTIONNUMBER
- return b ? m_expr1->evaluateToNumber(exec) : m_expr2->evaluateToNumber(exec);
-}
+ generator.emitLabel(beforeElse.get());
+ generator.emitNode(newDst.get(), m_expr2.get());
-int32_t ConditionalNode::evaluateToInt32(ExecState* exec)
-{
- bool b = m_logical->evaluateToBoolean(exec);
- KJS_CHECKEXCEPTIONNUMBER
- return b ? m_expr1->evaluateToInt32(exec) : m_expr2->evaluateToInt32(exec);
-}
+ generator.emitLabel(afterElse.get());
-uint32_t ConditionalNode::evaluateToUInt32(ExecState* exec)
-{
- bool b = m_logical->evaluateToBoolean(exec);
- KJS_CHECKEXCEPTIONNUMBER
- return b ? m_expr1->evaluateToUInt32(exec) : m_expr2->evaluateToUInt32(exec);
+ return newDst.get();
}
-// ECMA 11.13
+// ------------------------------ ReadModifyResolveNode -----------------------------------
-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)
+// FIXME: should this be moved to be a method on CodeGenerator?
+static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(CodeGenerator& generator, RegisterID* dst, RegisterID* src1, RegisterID* src2, Operator oper, OperandTypes types)
{
- JSValue* v;
- int i1;
- int i2;
- unsigned int ui;
+ OpcodeID opcode;
switch (oper) {
case OpMultEq:
- v = jsNumber(current->toNumber(exec) * right->evaluateToNumber(exec));
+ opcode = op_mul;
break;
case OpDivEq:
- v = jsNumber(current->toNumber(exec) / right->evaluateToNumber(exec));
+ opcode = op_div;
break;
case OpPlusEq:
- v = add(exec, current, right->evaluate(exec));
+ opcode = op_add;
break;
case OpMinusEq:
- v = jsNumber(current->toNumber(exec) - right->evaluateToNumber(exec));
+ opcode = op_sub;
break;
case OpLShift:
- i1 = current->toInt32(exec);
- i2 = right->evaluateToInt32(exec);
- v = jsNumber(i1 << i2);
+ opcode = op_lshift;
break;
case OpRShift:
- i1 = current->toInt32(exec);
- i2 = right->evaluateToInt32(exec);
- v = jsNumber(i1 >> i2);
+ opcode = op_rshift;
break;
case OpURShift:
- ui = current->toUInt32(exec);
- i2 = right->evaluateToInt32(exec);
- v = jsNumber(ui >> i2);
+ opcode = op_urshift;
break;
case OpAndEq:
- i1 = current->toInt32(exec);
- i2 = right->evaluateToInt32(exec);
- v = jsNumber(i1 & i2);
+ opcode = op_bitand;
break;
case OpXOrEq:
- i1 = current->toInt32(exec);
- i2 = right->evaluateToInt32(exec);
- v = jsNumber(i1 ^ i2);
+ opcode = op_bitxor;
break;
case OpOrEq:
- i1 = current->toInt32(exec);
- i2 = right->evaluateToInt32(exec);
- v = jsNumber(i1 | i2);
+ opcode = op_bitor;
break;
- case OpModEq: {
- double d1 = current->toNumber(exec);
- double d2 = right->evaluateToNumber(exec);
- v = jsNumber(fmod(d1, d2));
- }
+ case OpModEq:
+ opcode = op_mod;
break;
default:
ASSERT_NOT_REACHED();
- v = jsUndefined();
+ return dst;
}
-
- return v;
+
+ return generator.emitBinaryOp(opcode, dst, src1, src2, types);
}
-// ------------------------------ ReadModifyResolveNode -----------------------------------
-
-void ReadModifyResolveNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
+RegisterID* ReadModifyResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ if (RegisterID* local = generator.registerFor(m_ident)) {
+ if (generator.isLocalConstant(m_ident)) {
+ RegisterID* src2 = generator.emitNode(m_right.get());
+ return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
+ }
+
+ if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) {
+ RefPtr<RegisterID> result = generator.newTemporary();
+ generator.emitMove(result.get(), local);
+ RegisterID* src2 = generator.emitNode(m_right.get());
+ emitReadModifyAssignment(generator, result.get(), result.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
+ generator.emitMove(local, result.get());
+ return generator.moveToDestinationIfNeeded(dst, result.get());
+ }
+
+ RegisterID* src2 = generator.emitNode(m_right.get());
+ RegisterID* result = emitReadModifyAssignment(generator, local, local, src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
+ return generator.moveToDestinationIfNeeded(dst, result);
}
-}
-// ------------------------------ 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);
+ int index = 0;
+ size_t depth = 0;
+ JSObject* globalObject = 0;
+ if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) {
+ RefPtr<RegisterID> src1 = generator.emitGetScopedVar(generator.tempDestination(dst), depth, index, globalObject);
+ RegisterID* src2 = generator.emitNode(m_right.get());
+ RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
+ generator.emitPutScopedVar(depth, index, result, globalObject);
+ return result;
}
-}
-// ------------------------------ 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;
+ RefPtr<RegisterID> src1 = generator.tempDestination(dst);
+ generator.emitExpressionInfo(m_divot - m_startOffset + m_ident.size(), m_ident.size(), 0);
+ RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident);
+ RegisterID* src2 = generator.emitNode(m_right.get());
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), src2, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
+ return generator.emitPutById(base.get(), m_ident, result);
}
-// ------------------------------ 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 -----------------------------------
+// ------------------------------ AssignResolveNode -----------------------------------
-JSValue* ReadModifyConstNode::evaluate(ExecState* exec)
+RegisterID* AssignResolveNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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;
-}
+ if (RegisterID* local = generator.registerFor(m_ident)) {
+ if (generator.isLocalConstant(m_ident))
+ return generator.emitNode(dst, m_right.get());
+
+ RegisterID* result = generator.emitNode(local, m_right.get());
+ return generator.moveToDestinationIfNeeded(dst, result);
+ }
-// ------------------------------ AssignConstNode -----------------------------------
+ int index = 0;
+ size_t depth = 0;
+ JSObject* globalObject = 0;
+ if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) {
+ if (dst == ignoredResult())
+ dst = 0;
+ RegisterID* value = generator.emitNode(dst, m_right.get());
+ generator.emitPutScopedVar(depth, index, value, globalObject);
+ return value;
+ }
-JSValue* AssignConstNode::evaluate(ExecState* exec)
-{
- return m_right->evaluate(exec);
+ RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident);
+ if (dst == ignoredResult())
+ dst = 0;
+ RegisterID* value = generator.emitNode(dst, m_right.get());
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ return generator.emitPutById(base.get(), m_ident, value);
}
-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);
+// ------------------------------ AssignDotNode -----------------------------------
-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)
+RegisterID* AssignDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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;
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator));
+ RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
+ RegisterID* result = generator.emitNode(value.get(), m_right.get());
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ generator.emitPutById(base.get(), m_ident, result);
+ return generator.moveToDestinationIfNeeded(dst, result);
}
// ------------------------------ 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)
+RegisterID* ReadModifyDotNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* baseValue = m_base->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
- JSObject* base = baseValue->toObject(exec);
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_rightHasAssignments, m_right->isPure(generator));
- JSValue* v;
+ generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
+ RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident);
+ RegisterID* change = generator.emitNode(m_right.get());
+ RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
- 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;
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ return generator.emitPutById(base.get(), m_ident, updatedValue);
}
// ------------------------------ AssignErrorNode -----------------------------------
-JSValue* AssignErrorNode::evaluate(ExecState* exec)
+RegisterID* AssignErrorNode::emitCode(CodeGenerator& generator, RegisterID*)
{
- throwError(exec, ReferenceError, "Left side of assignment is not a reference.");
- handleException(exec);
- return jsUndefined();
+ return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference.");
}
// ------------------------------ 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)
+RegisterID* AssignBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* baseValue = m_base->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
- JSValue* subscript = m_subscript->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
-
- JSObject* base = baseValue->toObject(exec);
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator));
+ RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator));
+ RefPtr<RegisterID> value = generator.destinationForAssignResult(dst);
+ RegisterID* result = generator.emitNode(value.get(), m_right.get());
- 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());
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ generator.emitPutByVal(base.get(), property.get(), result);
+ return generator.moveToDestinationIfNeeded(dst, result);
}
-JSValue* ReadModifyBracketNode::evaluate(ExecState* exec)
+RegisterID* ReadModifyBracketNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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;
+ RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base.get(), m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator));
+ RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript.get(), m_rightHasAssignments, m_right->isPure(generator));
- 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);
+ generator.emitExpressionInfo(m_divot - m_subexpressionDivotOffset, m_startOffset - m_subexpressionDivotOffset, m_subexpressionEndOffset);
+ RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get());
+ RegisterID* change = generator.emitNode(m_right.get());
+ RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), change, m_operator, OperandTypes(ResultType::unknown(), m_right->resultDescriptor()));
- KJS_CHECKEXCEPTIONVALUE
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ generator.emitPutByVal(base.get(), property.get(), updatedValue);
- base->put(exec, propertyName, v);
- return v;
+ return updatedValue;
}
// ------------------------------ 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)
+RegisterID* CommaNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- m_expr1->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
- return m_expr2->evaluate(exec);
+ generator.emitNode(ignoredResult(), m_expr1.get());
+ return generator.emitNode(dst, m_expr2.get());
}
// ------------------------------ ConstDeclNode ----------------------------------
-ConstDeclNode::ConstDeclNode(const Identifier& ident, ExpressionNode* init)
- : m_ident(ident)
+ConstDeclNode::ConstDeclNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* init)
+ : ExpressionNode(globalData)
+ , m_ident(ident)
, m_init(init)
{
}
-void ConstDeclNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* ConstDeclNode::emitCodeSingle(CodeGenerator& generator)
{
- 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;
+ if (RegisterID* local = generator.constRegisterFor(m_ident)) {
+ if (!m_init)
+ return local;
- do {
- base = *iter;
- if (base->getPropertySlot(exec, m_ident, slot))
- break;
-
- ++iter;
- } while (iter != end);
-
- unsigned flags = 0;
- base->getPropertyAttributes(m_ident, flags);
- flags |= ReadOnly;
-
- base->put(exec, m_ident, val, flags);
-}
-
-// 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();
- JSObject* variableObject = exec->variableObject();
-
- ASSERT(!chain.isEmpty());
-
- bool inGlobalScope = ++chain.begin() == chain.end();
-
- if (m_init) {
- if (inGlobalScope) {
- JSValue* val = m_init->evaluate(exec);
- int flags = Internal;
- if (exec->codeType() != EvalCode)
- flags |= DontDelete;
- flags |= ReadOnly;
- variableObject->put(exec, m_ident, val, flags);
- } 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);
-
- unsigned flags = 0;
- variableObject->getPropertyAttributes(m_ident, flags);
- flags |= ReadOnly;
-
- variableObject->put(exec, m_ident, val, flags);
- }
+ return generator.emitNode(local, m_init.get());
}
+
+ // FIXME: While this code should only be hit in eval code, it will potentially
+ // assign to the wrong base if m_ident exists in an intervening dynamic scope.
+ RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident);
+ RegisterID* value = m_init ? generator.emitNode(m_init.get()) : generator.emitLoad(0, jsUndefined());
+ return generator.emitPutById(base.get(), m_ident, value);
}
-JSValue* ConstDeclNode::evaluate(ExecState* exec)
+RegisterID* ConstDeclNode::emitCode(CodeGenerator& generator, RegisterID*)
{
- evaluateSingle(exec);
-
- if (ConstDeclNode* n = m_next.get()) {
- do {
- n->evaluateSingle(exec);
- KJS_CHECKEXCEPTIONVALUE
- n = n->m_next.get();
- } while (n);
- }
- return jsUndefined();
+ RegisterID* result = 0;
+ for (ConstDeclNode* n = this; n; n = n->m_next.get())
+ result = n->emitCodeSingle(generator);
+
+ return result;
}
// ------------------------------ ConstStatementNode -----------------------------
-void ConstStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* ConstStatementNode::emitCode(CodeGenerator& generator, RegisterID*)
{
- 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();
+ return generator.emitNode(m_next.get());
}
// ------------------------------ Helper functions for handling Vectors of StatementNode -------------------------------
-static inline void statementListPushFIFO(StatementVector& statements, DeclarationStacks::NodeStack& stack)
+static inline RegisterID* statementListEmitCode(StatementVector& statements, CodeGenerator& generator, RegisterID* dst)
{
- StatementVector::iterator it = statements.end();
- StatementVector::iterator begin = statements.begin();
- while (it != begin) {
- --it;
- stack.append((*it).get());
+ StatementVector::iterator end = statements.end();
+ for (StatementVector::iterator it = statements.begin(); it != end; ++it) {
+ StatementNode* n = it->get();
+ if (!n->isLoop())
+ generator.emitDebugHook(WillExecuteStatement, n->firstLine(), n->lastLine());
+ generator.emitNode(dst, n);
}
+ return 0;
}
-static inline Node* statementListInitializeVariableAccessStack(StatementVector& statements, DeclarationStacks::NodeStack& stack)
+static inline void statementListPushFIFO(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) {
+ while (it != begin) {
--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)
+BlockNode::BlockNode(JSGlobalData* globalData, SourceElements* children)
+ : StatementNode(globalData)
{
if (children)
children->releaseContentsIntoVector(m_children);
}
-void BlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* BlockNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- statementListPushFIFO(m_children, nodeStack);
+ return statementListEmitCode(m_children, generator, dst);
}
-// ECMA 12.1
-JSValue* BlockNode::execute(ExecState* exec)
+// ------------------------------ EmptyStatementNode ---------------------------
+
+RegisterID* EmptyStatementNode::emitCode(CodeGenerator&, RegisterID* dst)
{
- return statementListExecute(m_children, exec);
+ return dst;
}
-// ------------------------------ EmptyStatementNode ---------------------------
+// ------------------------------ DebuggerStatementNode ---------------------------
-// ECMA 12.3
-JSValue* EmptyStatementNode::execute(ExecState* exec)
+RegisterID* DebuggerStatementNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- return exec->setNormalCompletion();
+ generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine());
+ return dst;
}
// ------------------------------ ExprStatementNode ----------------------------
-void ExprStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* ExprStatementNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
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);
+ return generator.emitNode(dst, m_expr.get());
}
// ------------------------------ VarStatementNode ----------------------------
-void VarStatementNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* VarStatementNode::emitCode(CodeGenerator& generator, RegisterID*)
{
ASSERT(m_expr);
- nodeStack.append(m_expr.get());
+ return generator.emitNode(m_expr.get());
}
-JSValue* VarStatementNode::execute(ExecState* exec)
+// ------------------------------ IfNode ---------------------------------------
+
+RegisterID* IfNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- m_expr->evaluate(exec);
- KJS_CHECKEXCEPTION
+ RefPtr<LabelID> afterThen = generator.newLabel();
- return exec->setNormalCompletion();
-}
+ RegisterID* cond = generator.emitNode(m_condition.get());
+ generator.emitJumpIfFalse(cond, afterThen.get());
-// ------------------------------ IfNode ---------------------------------------
+ if (!m_ifBlock->isBlock())
+ generator.emitDebugHook(WillExecuteStatement, m_ifBlock->firstLine(), m_ifBlock->lastLine());
-void IfNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
-{
- nodeStack.append(m_ifBlock.get());
- nodeStack.append(m_condition.get());
+ generator.emitNode(dst, m_ifBlock.get());
+ generator.emitLabel(afterThen.get());
+
+ // FIXME: This should return the last statement exectuted so that it can be returned as a Completion
+ return 0;
}
-// ECMA 12.5
-JSValue* IfNode::execute(ExecState* exec)
+RegisterID* IfElseNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- bool b = m_condition->evaluateToBoolean(exec);
- KJS_CHECKEXCEPTION
+ RefPtr<LabelID> beforeElse = generator.newLabel();
+ RefPtr<LabelID> afterElse = generator.newLabel();
- if (b)
- return m_ifBlock->execute(exec);
- return exec->setNormalCompletion();
-}
+ RegisterID* cond = generator.emitNode(m_condition.get());
+ generator.emitJumpIfFalse(cond, beforeElse.get());
-void IfElseNode::optimizeVariableAccess(const SymbolTable& symbolTable, const LocalStorage& localStorage, NodeStack& nodeStack)
-{
- nodeStack.append(m_elseBlock.get());
- IfNode::optimizeVariableAccess(symbolTable, localStorage, nodeStack);
-}
+ if (!m_ifBlock->isBlock())
+ generator.emitDebugHook(WillExecuteStatement, m_ifBlock->firstLine(), m_ifBlock->lastLine());
-// ECMA 12.5
-JSValue* IfElseNode::execute(ExecState* exec)
-{
- bool b = m_condition->evaluateToBoolean(exec);
- KJS_CHECKEXCEPTION
+ generator.emitNode(dst, m_ifBlock.get());
+ generator.emitJump(afterElse.get());
- if (b)
- return m_ifBlock->execute(exec);
- return m_elseBlock->execute(exec);
-}
+ generator.emitLabel(beforeElse.get());
-// ------------------------------ DoWhileNode ----------------------------------
+ if (!m_elseBlock->isBlock())
+ generator.emitDebugHook(WillExecuteStatement, m_elseBlock->firstLine(), m_elseBlock->lastLine());
-void DoWhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
-{
- nodeStack.append(m_statement.get());
- nodeStack.append(m_expr.get());
+ generator.emitNode(dst, m_elseBlock.get());
+
+ generator.emitLabel(afterElse.get());
+
+ // FIXME: This should return the last statement exectuted so that it can be returned as a Completion
+ return 0;
}
-// ECMA 12.6.1
-JSValue* DoWhileNode::execute(ExecState* exec)
+// ------------------------------ DoWhileNode ----------------------------------
+
+RegisterID* DoWhileNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* value = 0;
+ RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
- while (1) {
- exec->pushIteration();
- JSValue* statementValue = m_statement->execute(exec);
- exec->popIteration();
+ RefPtr<LabelID> topOfLoop = generator.newLabel();
+ generator.emitLabel(topOfLoop.get());
- if (exec->dynamicGlobalObject()->timedOut())
- return exec->setInterruptedCompletion();
+ generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
- if (statementValue)
- value = statementValue;
+ if (!m_statement->isBlock())
+ generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine());
+
+ RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get());
- 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;
- }
+ generator.emitLabel(scope->continueTarget());
+ generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo());
+ RegisterID* cond = generator.emitNode(m_expr.get());
+ generator.emitJumpIfTrue(cond, topOfLoop.get());
- continueDoWhileLoop:
- bool b = m_expr->evaluateToBoolean(exec);
- KJS_CHECKEXCEPTION
- if (!b)
- break;
- }
-
- return exec->setNormalCompletion(value);
+ generator.emitLabel(scope->breakTarget());
+ return result.get();
}
// ------------------------------ WhileNode ------------------------------------
-void WhileNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* WhileNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- nodeStack.append(m_statement.get());
- nodeStack.append(m_expr.get());
-}
+ RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
-// 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;
+ generator.emitJump(scope->continueTarget());
- exec->pushIteration();
- JSValue* statementValue = m_statement->execute(exec);
- exec->popIteration();
+ RefPtr<LabelID> topOfLoop = generator.newLabel();
+ generator.emitLabel(topOfLoop.get());
- if (exec->dynamicGlobalObject()->timedOut())
- return exec->setInterruptedCompletion();
+ if (!m_statement->isBlock())
+ generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine());
+
+ generator.emitNode(dst, m_statement.get());
- if (statementValue)
- value = statementValue;
+ generator.emitLabel(scope->continueTarget());
+ generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo());
+ RegisterID* cond = generator.emitNode(m_expr.get());
+ generator.emitJumpIfTrue(cond, topOfLoop.get());
- 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);
+ generator.emitLabel(scope->breakTarget());
+
+ // FIXME: This should return the last statement executed so that it can be returned as a Completion
+ return 0;
}
// ------------------------------ ForNode --------------------------------------
-void ForNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* ForNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- nodeStack.append(m_statement.get());
- nodeStack.append(m_expr3.get());
- nodeStack.append(m_expr2.get());
- nodeStack.append(m_expr1.get());
-}
+ if (dst == ignoredResult())
+ dst = 0;
-// ECMA 12.6.3
-JSValue* ForNode::execute(ExecState* exec)
-{
- JSValue* value = 0;
+ RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
- m_expr1->evaluate(exec);
- KJS_CHECKEXCEPTION
+ generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
- while (1) {
- bool b = m_expr2->evaluateToBoolean(exec);
- KJS_CHECKEXCEPTION
- if (!b)
- break;
+ if (m_expr1)
+ generator.emitNode(ignoredResult(), m_expr1.get());
- exec->pushIteration();
- JSValue* statementValue = m_statement->execute(exec);
- exec->popIteration();
- if (statementValue)
- value = statementValue;
+ RefPtr<LabelID> condition = generator.newLabel();
+ generator.emitJump(condition.get());
- if (exec->dynamicGlobalObject()->timedOut())
- return exec->setInterruptedCompletion();
+ RefPtr<LabelID> topOfLoop = generator.newLabel();
+ generator.emitLabel(topOfLoop.get());
- 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;
- }
+ if (!m_statement->isBlock())
+ generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine());
+ RefPtr<RegisterID> result = generator.emitNode(dst, m_statement.get());
- continueForLoop:
- m_expr3->evaluate(exec);
- KJS_CHECKEXCEPTION
- }
+ generator.emitLabel(scope->continueTarget());
+ if (m_expr3)
+ generator.emitNode(ignoredResult(), m_expr3.get());
- return exec->setNormalCompletion(value);
+ generator.emitLabel(condition.get());
+ if (m_expr2) {
+ RegisterID* cond = generator.emitNode(m_expr2.get());
+ generator.emitJumpIfTrue(cond, topOfLoop.get());
+ } else
+ generator.emitJump(topOfLoop.get());
+
+ generator.emitLabel(scope->breakTarget());
+ return result.get();
}
// ------------------------------ ForInNode ------------------------------------
-ForInNode::ForInNode(ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
- : m_init(0L)
+ForInNode::ForInNode(JSGlobalData* globalData, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement)
+ : StatementNode(globalData)
+ , m_init(0L)
, m_lexpr(l)
, m_expr(expr)
, m_statement(statement)
@@ -3934,791 +1274,609 @@ ForInNode::ForInNode(ExpressionNode* l, ExpressionNode* expr, StatementNode* sta
{
}
-ForInNode::ForInNode(const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement)
- : m_ident(ident)
- , m_lexpr(new ResolveNode(ident))
+ForInNode::ForInNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* in, ExpressionNode* expr, StatementNode* statement, int divot, int startOffset, int endOffset)
+ : StatementNode(globalData)
+ , m_ident(ident)
+ , m_lexpr(new ResolveNode(globalData, ident, divot - startOffset))
, m_expr(expr)
, m_statement(statement)
, m_identIsVarDecl(true)
{
- if (in)
- m_init = new AssignResolveNode(ident, in);
+ if (in) {
+ AssignResolveNode* node = new AssignResolveNode(globalData, ident, in, true);
+ node->setExceptionSourceCode(divot, divot - startOffset, endOffset - divot);
+ m_init = node;
+ }
// 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)
+RegisterID* ForInNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop);
- 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);
- }
+ if (!m_lexpr->isLocation())
+ return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference.");
- KJS_CHECKEXCEPTION
+ RefPtr<LabelID> continueTarget = generator.newLabel();
- exec->pushIteration();
- JSValue* statementValue = m_statement->execute(exec);
- exec->popIteration();
- if (statementValue)
- value = statementValue;
+ generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine());
- 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;
+ if (m_init)
+ generator.emitNode(ignoredResult(), m_init.get());
+ RegisterID* forInBase = generator.emitNode(m_expr.get());
+ RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), forInBase);
+ generator.emitJump(scope->continueTarget());
+
+ RefPtr<LabelID> loopStart = generator.newLabel();
+ generator.emitLabel(loopStart.get());
+
+ RegisterID* propertyName;
+ if (m_lexpr->isResolveNode()) {
+ const Identifier& ident = static_cast<ResolveNode*>(m_lexpr.get())->identifier();
+ propertyName = generator.registerFor(ident);
+ if (!propertyName) {
+ propertyName = generator.newTemporary();
+ RefPtr<RegisterID> protect = propertyName;
+ RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident);
+
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ generator.emitPutById(base, ident, propertyName);
}
- }
-
- return exec->setNormalCompletion(value);
+ } else if (m_lexpr->isDotAccessorNode()) {
+ DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr.get());
+ const Identifier& ident = assignNode->identifier();
+ propertyName = generator.newTemporary();
+ RefPtr<RegisterID> protect = propertyName;
+ RegisterID* base = generator.emitNode(assignNode->base());
+
+ generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset());
+ generator.emitPutById(base, ident, propertyName);
+ } else {
+ ASSERT(m_lexpr->isBracketAccessorNode());
+ BracketAccessorNode* assignNode = static_cast<BracketAccessorNode*>(m_lexpr.get());
+ propertyName = generator.newTemporary();
+ RefPtr<RegisterID> protect = propertyName;
+ RefPtr<RegisterID> base = generator.emitNode(assignNode->base());
+ RegisterID* subscript = generator.emitNode(assignNode->subscript());
+
+ generator.emitExpressionInfo(assignNode->divot(), assignNode->startOffset(), assignNode->endOffset());
+ generator.emitPutByVal(base.get(), subscript, propertyName);
+ }
+
+ if (!m_statement->isBlock())
+ generator.emitDebugHook(WillExecuteStatement, m_statement->firstLine(), m_statement->lastLine());
+ generator.emitNode(dst, m_statement.get());
+
+ generator.emitLabel(scope->continueTarget());
+ generator.emitNextPropertyName(propertyName, iter.get(), loopStart.get());
+ generator.emitLabel(scope->breakTarget());
+ return dst;
}
// ------------------------------ ContinueNode ---------------------------------
// ECMA 12.7
-JSValue* ContinueNode::execute(ExecState* exec)
+RegisterID* ContinueNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ LabelScope* scope = generator.continueTarget(m_ident);
+
+ if (!scope)
+ return m_ident.isEmpty()
+ ? emitThrowError(generator, SyntaxError, "Invalid continue statement.")
+ : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident);
+
+ generator.emitJumpScopes(scope->continueTarget(), scope->scopeDepth());
+ return dst;
}
// ------------------------------ BreakNode ------------------------------------
// ECMA 12.8
-JSValue* BreakNode::execute(ExecState* exec)
+RegisterID* BreakNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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);
+ LabelScope* scope = generator.breakTarget(m_ident);
+
+ if (!scope)
+ return m_ident.isEmpty()
+ ? emitThrowError(generator, SyntaxError, "Invalid break statement.")
+ : emitThrowError(generator, SyntaxError, "Undefined label: '%s'.", m_ident);
+
+ generator.emitJumpScopes(scope->breakTarget(), scope->scopeDepth());
+ return dst;
}
// ------------------------------ 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)
+RegisterID* ReturnNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- 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
+ if (generator.codeType() != FunctionCode)
+ return emitThrowError(generator, SyntaxError, "Invalid return statement.");
- return exec->setReturnValueCompletion(v);
+ if (dst == ignoredResult())
+ dst = 0;
+ RegisterID* r0 = m_value ? generator.emitNode(dst, m_value.get()) : generator.emitLoad(dst, jsUndefined());
+ if (generator.scopeDepth()) {
+ RefPtr<LabelID> l0 = generator.newLabel();
+ generator.emitJumpScopes(l0.get(), 0);
+ generator.emitLabel(l0.get());
+ }
+ generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
+ return generator.emitReturn(r0);
}
// ------------------------------ 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)
+RegisterID* WithNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- if (m_expr)
- nodeStack.append(m_expr.get());
- statementListPushFIFO(m_children, nodeStack);
+ RefPtr<RegisterID> scope = generator.emitNode(m_expr.get()); // scope must be protected until popped
+ generator.emitExpressionInfo(m_divot, m_expressionLength, 0);
+ generator.emitPushScope(scope.get());
+ RegisterID* result = generator.emitNode(dst, m_statement.get());
+ generator.emitPopScope();
+ return result;
}
-// ECMA 12.11
-JSValue* CaseClauseNode::evaluate(ExecState* exec)
-{
- JSValue* v = m_expr->evaluate(exec);
- KJS_CHECKEXCEPTIONVALUE
-
- return v;
-}
+// ------------------------------ CaseBlockNode --------------------------------
+enum SwitchKind {
+ SwitchUnset = 0,
+ SwitchNumber = 1,
+ SwitchString = 2,
+ SwitchNeither = 3
+};
-// ECMA 12.11
-JSValue* CaseClauseNode::executeStatements(ExecState* exec)
+static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num)
{
- return statementListExecute(m_children, exec);
+ for (; list; list = list->getNext()) {
+ ExpressionNode* clauseExpression = list->getClause()->expr();
+ literalVector.append(clauseExpression);
+ if (clauseExpression->isNumber()) {
+ double value = static_cast<NumberNode*>(clauseExpression)->value();
+ if ((typeForTable & ~SwitchNumber) || !JSImmediate::from(value)) {
+ typeForTable = SwitchNeither;
+ break;
+ }
+ int32_t intVal = static_cast<int32_t>(value);
+ ASSERT(intVal == value);
+ if (intVal < min_num)
+ min_num = intVal;
+ if (intVal > max_num)
+ max_num = intVal;
+ typeForTable = SwitchNumber;
+ continue;
+ }
+ if (clauseExpression->isString()) {
+ if (typeForTable & ~SwitchString) {
+ typeForTable = SwitchNeither;
+ break;
+ }
+ const UString& value = static_cast<StringNode*>(clauseExpression)->value().ustring();
+ if (singleCharacterSwitch &= value.size() == 1) {
+ int32_t intVal = value.rep()->data()[0];
+ if (intVal < min_num)
+ min_num = intVal;
+ if (intVal > max_num)
+ max_num = intVal;
+ }
+ typeForTable = SwitchString;
+ continue;
+ }
+ typeForTable = SwitchNeither;
+ break;
+ }
}
-
-// ------------------------------ ClauseListNode -------------------------------
-
-void ClauseListNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+
+SwitchInfo::SwitchType CaseBlockNode::tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num)
{
- if (m_next)
- nodeStack.append(m_next.get());
- nodeStack.append(m_clause.get());
-}
-
-// ------------------------------ CaseBlockNode --------------------------------
+ SwitchKind typeForTable = SwitchUnset;
+ bool singleCharacterSwitch = true;
+
+ processClauseList(m_list1.get(), literalVector, typeForTable, singleCharacterSwitch, min_num, max_num);
+ processClauseList(m_list2.get(), literalVector, typeForTable, singleCharacterSwitch, min_num, max_num);
+
+ if (typeForTable == SwitchUnset || typeForTable == SwitchNeither)
+ return SwitchInfo::SwitchNone;
+
+ if (typeForTable == SwitchNumber) {
+ int32_t range = max_num - min_num;
+ if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10)
+ return SwitchInfo::SwitchImmediate;
+ return SwitchInfo::SwitchNone;
+ }
+
+ ASSERT(typeForTable == SwitchString);
+
+ if (singleCharacterSwitch) {
+ int32_t range = max_num - min_num;
+ if (min_num <= max_num && range <= 1000 && (range / literalVector.size()) < 10)
+ return SwitchInfo::SwitchCharacter;
+ }
-CaseBlockNode::CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2)
- : m_list1(list1)
- , m_defaultClause(defaultClause)
- , m_list2(list2)
-{
+ return SwitchInfo::SwitchString;
}
-void CaseBlockNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* CaseBlockNode::emitCodeForBlock(CodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst)
{
- if (m_list2)
- nodeStack.append(m_list2.get());
- if (m_defaultClause)
- nodeStack.append(m_defaultClause.get());
- if (m_list1)
- nodeStack.append(m_list1.get());
-}
+ RefPtr<LabelID> defaultLabel;
+ Vector<RefPtr<LabelID>, 8> labelVector;
+ Vector<ExpressionNode*, 8> literalVector;
+ int32_t min_num = std::numeric_limits<int32_t>::max();
+ int32_t max_num = std::numeric_limits<int32_t>::min();
+ SwitchInfo::SwitchType switchType = tryOptimizedSwitch(literalVector, min_num, max_num);
-// 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;
+ if (switchType != SwitchInfo::SwitchNone) {
+ // Prepare the various labels
+ for (uint32_t i = 0; i < literalVector.size(); i++)
+ labelVector.append(generator.newLabel());
+ defaultLabel = generator.newLabel();
+ generator.beginSwitch(switchExpression, switchType);
+ } else {
+ // Setup jumps
+ for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) {
+ RefPtr<RegisterID> clauseVal = generator.newTemporary();
+ generator.emitNode(clauseVal.get(), list->getClause()->expr());
+ generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes());
+ labelVector.append(generator.newLabel());
+ generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get());
+ }
+
+ for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) {
+ RefPtr<RegisterID> clauseVal = generator.newTemporary();
+ generator.emitNode(clauseVal.get(), list->getClause()->expr());
+ generator.emitBinaryOp(op_stricteq, clauseVal.get(), clauseVal.get(), switchExpression, OperandTypes());
+ labelVector.append(generator.newLabel());
+ generator.emitJumpIfTrue(clauseVal.get(), labelVector[labelVector.size() - 1].get());
}
+ defaultLabel = generator.newLabel();
+ generator.emitJump(defaultLabel.get());
}
- 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;
- }
+ RegisterID* result = 0;
+
+ size_t i = 0;
+ for (ClauseListNode* list = m_list1.get(); list; list = list->getNext()) {
+ generator.emitLabel(labelVector[i++].get());
+ result = statementListEmitCode(list->getClause()->children(), generator, dst);
}
- // 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();
+ generator.emitLabel(defaultLabel.get());
+ result = statementListEmitCode(m_defaultClause->children(), generator, dst);
}
- // bail out on error
- KJS_CHECKEXCEPTION
+ for (ClauseListNode* list = m_list2.get(); list; list = list->getNext()) {
+ generator.emitLabel(labelVector[i++].get());
+ result = statementListEmitCode(list->getClause()->children(), generator, dst);
+ }
+ if (!m_defaultClause)
+ generator.emitLabel(defaultLabel.get());
- return exec->setNormalCompletion();
+ ASSERT(i == labelVector.size());
+ if (switchType != SwitchInfo::SwitchNone) {
+ ASSERT(labelVector.size() == literalVector.size());
+ generator.endSwitch(labelVector.size(), labelVector.data(), literalVector.data(), defaultLabel.get(), min_num, max_num);
+ }
+ return result;
}
// ------------------------------ 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)
+RegisterID* SwitchNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* v = m_expr->evaluate(exec);
- KJS_CHECKEXCEPTION
+ RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch);
- exec->pushSwitch();
- JSValue* result = m_block->executeBlock(exec, v);
- exec->popSwitch();
+ RefPtr<RegisterID> r0 = generator.emitNode(m_expr.get());
+ RegisterID* r1 = m_block->emitCodeForBlock(generator, r0.get(), dst);
- if (exec->completionType() == Break && m_labelStack.contains(exec->breakOrContinueTarget()))
- exec->setCompletionType(Normal);
- return result;
+ generator.emitLabel(scope->breakTarget());
+ return r1;
}
// ------------------------------ LabelNode ------------------------------------
-void LabelNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* LabelNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- nodeStack.append(m_statement.get());
-}
+ if (generator.breakTarget(m_name))
+ return emitThrowError(generator, SyntaxError, "Duplicate label: %s.", m_name);
-// 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();
+ RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name);
+ RegisterID* r0 = generator.emitNode(dst, m_statement.get());
- if (exec->completionType() == Break && exec->breakOrContinueTarget() == m_label)
- exec->setCompletionType(Normal);
- return result;
+ generator.emitLabel(scope->breakTarget());
+ return r0;
}
// ------------------------------ ThrowNode ------------------------------------
-void ThrowNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
-{
- nodeStack.append(m_expr.get());
-}
-
-// ECMA 12.13
-JSValue* ThrowNode::execute(ExecState* exec)
+RegisterID* ThrowNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- JSValue* v = m_expr->evaluate(exec);
- KJS_CHECKEXCEPTION
-
- handleException(exec, v);
- return exec->setThrowCompletion(v);
+ if (dst == ignoredResult())
+ dst = 0;
+ RefPtr<RegisterID> expr = generator.emitNode(dst, m_expr.get());
+ generator.emitExpressionInfo(m_divot, m_startOffset, m_endOffset);
+ generator.emitThrow(expr.get());
+ return dst;
}
// ------------------------------ TryNode --------------------------------------
-void TryNode::optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack& nodeStack)
+RegisterID* TryNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- // Can't optimize within catchBlock because "catch" introduces a dynamic scope.
- if (m_finallyBlock)
- nodeStack.append(m_finallyBlock.get());
- nodeStack.append(m_tryBlock.get());
-}
+ RefPtr<LabelID> tryStartLabel = generator.newLabel();
+ RefPtr<LabelID> tryEndLabel = generator.newLabel();
+ RefPtr<LabelID> finallyStart;
+ RefPtr<RegisterID> finallyReturnAddr;
+ if (m_finallyBlock) {
+ finallyStart = generator.newLabel();
+ finallyReturnAddr = generator.newTemporary();
+ generator.pushFinallyContext(finallyStart.get(), finallyReturnAddr.get());
+ }
+ generator.emitLabel(tryStartLabel.get());
+ generator.emitNode(dst, m_tryBlock.get());
+ generator.emitLabel(tryEndLabel.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->put(exec, m_exceptionIdent, result, DontDelete);
- exec->dynamicGlobalObject()->tearOffActivation(exec);
- exec->pushScope(obj);
- result = m_catchBlock->execute(exec);
- exec->popScope();
+ if (m_catchBlock) {
+ RefPtr<LabelID> handlerEndLabel = generator.newLabel();
+ generator.emitJump(handlerEndLabel.get());
+ RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), tryEndLabel.get());
+ generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get());
+ generator.emitNode(dst, m_catchBlock.get());
+ generator.emitPopScope();
+ generator.emitLabel(handlerEndLabel.get());
}
if (m_finallyBlock) {
- ComplType savedCompletionType = exec->completionType();
- JSValue* finallyResult = m_finallyBlock->execute(exec);
- if (exec->completionType() != Normal)
- result = finallyResult;
- else
- exec->setCompletionType(savedCompletionType);
+ generator.popFinallyContext();
+ // there may be important registers live at the time we jump
+ // to a finally block (such as for a return or throw) so we
+ // ref the highest register ever used as a conservative
+ // approach to not clobbering anything important
+ RefPtr<RegisterID> highestUsedRegister = generator.highestUsedRegister();
+ RefPtr<LabelID> finallyEndLabel = generator.newLabel();
+ generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get());
+ // Use a label to record the subtle fact that sret will return to the
+ // next instruction. sret is the only way to jump without an explicit label.
+ generator.emitLabel(generator.newLabel().get());
+ generator.emitJump(finallyEndLabel.get());
+
+ // Finally block for exception path
+ RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), generator.emitLabel(generator.newLabel().get()).get());
+ generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get());
+ // Use a label to record the subtle fact that sret will return to the
+ // next instruction. sret is the only way to jump without an explicit label.
+ generator.emitLabel(generator.newLabel().get());
+ generator.emitThrow(tempExceptionRegister.get());
+
+ // emit the finally block itself
+ generator.emitLabel(finallyStart.get());
+ generator.emitNode(dst, m_finallyBlock.get());
+ generator.emitSubroutineReturn(finallyReturnAddr.get());
+
+ generator.emitLabel(finallyEndLabel.get());
}
- return result;
+ return dst;
}
-// ------------------------------ FunctionBodyNode -----------------------------
-ScopeNode::ScopeNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
- : BlockNode(children)
- , m_sourceURL(parser().sourceURL())
- , m_sourceId(parser().sourceId())
+// ------------------------------ ScopeNode -----------------------------
+
+ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants)
+ : BlockNode(globalData, children)
+ , m_source(source)
+ , m_features(features)
+ , m_numConstants(numConstants)
{
if (varStack)
m_varStack = *varStack;
if (funcStack)
m_functionStack = *funcStack;
+#if ENABLE(OPCODE_SAMPLING)
+ globalData->machine->sampler()->notifyOfScope(this);
+#endif
}
// ------------------------------ ProgramNode -----------------------------
-ProgramNode::ProgramNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
- : ScopeNode(children, varStack, funcStack)
+ProgramNode::ProgramNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants)
{
}
-ProgramNode* ProgramNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
+ProgramNode* ProgramNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
{
- return new ProgramNode(children, varStack, funcStack);
+ return new ProgramNode(globalData, children, varStack, funcStack, source, features, numConstants);
}
// ------------------------------ EvalNode -----------------------------
-EvalNode::EvalNode(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
- : ScopeNode(children, varStack, funcStack)
+EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, source, children, varStack, funcStack, features, numConstants)
{
}
-EvalNode* EvalNode::create(SourceElements* children, VarStack* varStack, FunctionStack* funcStack)
+RegisterID* EvalNode::emitCode(CodeGenerator& generator, RegisterID*)
{
- return new EvalNode(children, varStack, funcStack);
-}
+ generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine());
-// ------------------------------ FunctionBodyNode -----------------------------
+ RefPtr<RegisterID> dstRegister = generator.newTemporary();
+ generator.emitLoad(dstRegister.get(), jsUndefined());
+ statementListEmitCode(m_children, generator, dstRegister.get());
-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);
+ generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
+ generator.emitEnd(dstRegister.get());
+ return 0;
}
-void FunctionBodyNode::initializeSymbolTable(ExecState* exec)
+void EvalNode::generateCode(ScopeChainNode* scopeChainNode)
{
- SymbolTable& symbolTable = exec->variableObject()->symbolTable();
- ASSERT(symbolTable.isEmpty());
-
- size_t localStorageIndex = 0;
-
- // Order must match the order in processDeclarations.
+ ScopeChain scopeChain(scopeChainNode);
+ JSGlobalObject* globalObject = scopeChain.globalObject();
- 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);
- }
+ SymbolTable symbolTable;
+ m_code.set(new EvalCodeBlock(this, globalObject, source().provider()));
- 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);
- }
+ CodeGenerator generator(this, globalObject->debugger(), scopeChain, &symbolTable, m_code.get());
+ generator.generate();
}
-void ProgramNode::initializeSymbolTable(ExecState* exec)
+EvalNode* EvalNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants)
{
- // 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;
- }
+ return new EvalNode(globalData, children, varStack, funcStack, source, features, numConstants);
+}
- 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;
- }
+// ------------------------------ FunctionBodyNode -----------------------------
- m_varIndexes[i] = result.first->second;
- ++localStorageIndex;
- }
+FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+ : ScopeNode(globalData, sourceCode, children, varStack, funcStack, features, numConstants)
+ , m_parameters(0)
+ , m_parameterCount(0)
+ , m_refCount(0)
+{
}
-void ScopeNode::optimizeVariableAccess(ExecState* exec)
+FunctionBodyNode::~FunctionBodyNode()
{
- 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);
- }
+ if (m_parameters)
+ fastFree(m_parameters);
}
-void FunctionBodyNode::processDeclarations(ExecState* exec)
+void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter)
{
- 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);
+ Vector<Identifier> parameters;
+ for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam())
+ parameters.append(parameter->ident());
+ size_t count = parameters.size();
- int minAttributes = Internal | 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;
- }
+ setSource(source);
+ finishParsing(parameters.releaseBuffer(), count);
}
-static void gccIsCrazy() KJS_FAST_CALL;
-static void gccIsCrazy()
+void FunctionBodyNode::finishParsing(Identifier* parameters, size_t parameterCount)
{
+ ASSERT(!source().isNull());
+ m_parameters = parameters;
+ m_parameterCount = parameterCount;
}
-void ProgramNode::processDeclarations(ExecState* exec)
+void FunctionBodyNode::mark()
{
- // 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 = Internal | DontDelete;
+ if (m_code)
+ m_code->mark();
+}
- // In order for our localStorage indexes to be correct, we must match the
- // order of addition in initializeSymbolTable().
+FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants)
+{
+ return new FunctionBodyNode(globalData, children, varStack, funcStack, SourceCode(), features, numConstants);
+}
- 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];
+FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& sourceCode, CodeFeatures features, int numConstants)
+{
+ return new FunctionBodyNode(globalData, children, varStack, funcStack, sourceCode, features, numConstants);
+}
- if (index == localStorage.size())
- localStorage.uncheckedAppend(entry);
- else {
- ASSERT(index < localStorage.size());
- localStorage[index] = entry;
- }
- }
+void FunctionBodyNode::generateCode(ScopeChainNode* scopeChainNode)
+{
+ ScopeChain scopeChain(scopeChainNode);
+ JSGlobalObject* globalObject = scopeChain.globalObject();
- for (size_t i = 0, size = m_varStack.size(); i < size; ++i) {
- size_t index = m_varIndexes[i];
- if (index == missingSymbolMarker())
- continue;
+ m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset()));
- int attributes = minAttributes;
- if (m_varStack[i].second & DeclarationStacks::IsConstant)
- attributes |= ReadOnly;
- LocalStorageEntry entry = LocalStorageEntry(jsUndefined(), attributes);
+ CodeGenerator generator(this, globalObject->debugger(), scopeChain, &m_symbolTable, m_code.get());
+ generator.generate();
+}
- ASSERT(index == localStorage.size());
- localStorage.uncheckedAppend(entry);
+RegisterID* FunctionBodyNode::emitCode(CodeGenerator& generator, RegisterID*)
+{
+ generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine());
+ statementListEmitCode(m_children, generator, ignoredResult());
+ if (!m_children.size() || !m_children.last()->isReturnNode()) {
+ RegisterID* r0 = generator.emitLoad(0, jsUndefined());
+ generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine());
+ generator.emitReturn(r0);
}
-
- optimizeVariableAccess(exec);
+ return 0;
}
-void EvalNode::processDeclarations(ExecState* exec)
+RegisterID* ProgramNode::emitCode(CodeGenerator& generator, RegisterID*)
{
- // 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();
+ generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine());
- int minAttributes = Internal;
+ RefPtr<RegisterID> dstRegister = generator.newTemporary();
+ generator.emitLoad(dstRegister.get(), jsUndefined());
+ statementListEmitCode(m_children, generator, dstRegister.get());
- for (i = 0, size = m_varStack.size(); i < size; ++i) {
- Identifier& ident = m_varStack[i].first;
- if (variableObject->hasProperty(exec, ident))
- continue;
- int attributes = minAttributes;
- if (m_varStack[i].second & DeclarationStacks::IsConstant)
- attributes |= ReadOnly;
- variableObject->put(exec, ident, jsUndefined(), attributes);
- }
+ generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine());
+ generator.emitEnd(dstRegister.get());
+ return 0;
+}
- for (i = 0, size = m_functionStack.size(); i < size; ++i) {
- FuncDeclNode* node = m_functionStack[i];
- variableObject->put(exec, node->m_ident, node->makeFunction(exec), minAttributes);
- }
+void ProgramNode::generateCode(ScopeChainNode* scopeChainNode)
+{
+ ScopeChain scopeChain(scopeChainNode);
+ JSGlobalObject* globalObject = scopeChain.globalObject();
+
+ m_code.set(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider()));
+
+ CodeGenerator generator(this, globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_code.get(), m_varStack, m_functionStack);
+ generator.generate();
}
UString FunctionBodyNode::paramString() const
{
UString s("");
- size_t count = m_parameters.size();
- for (size_t pos = 0; pos < count; ++pos) {
+ for (size_t pos = 0; pos < m_parameterCount; ++pos) {
if (!s.isEmpty())
s += ", ";
- s += m_parameters[pos].ustring();
+ s += parameters()[pos].ustring();
}
return s;
}
-JSValue* ProgramNode::execute(ExecState* exec)
+Identifier* FunctionBodyNode::copyParameters()
{
- 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())) {
- dbg->imp()->abort();
- 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())) {
- dbg->imp()->abort();
- return exec->setInterruptedCompletion();
- }
- }
-
- return result;
+ Identifier* parameters = static_cast<Identifier*>(fastMalloc(m_parameterCount * sizeof(Identifier)));
+ VectorCopier<false, Identifier>::uninitializedCopy(m_parameters, m_parameters + m_parameterCount, parameters);
+ return parameters;
}
// ------------------------------ FuncDeclNode ---------------------------------
-void FuncDeclNode::addParams()
+JSFunction* FuncDeclNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain)
{
- for (ParameterNode* p = m_parameter.get(); p; p = p->nextParam())
- m_body->parameters().append(p->ident());
+ return new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain);
}
-FunctionImp* FuncDeclNode::makeFunction(ExecState* exec)
+RegisterID* FuncDeclNode::emitCode(CodeGenerator&, RegisterID* dst)
{
- 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, ReadOnly | DontDelete | DontEnum);
- func->putDirect(exec->propertyNames().prototype, proto, Internal | DontDelete);
- func->putDirect(exec->propertyNames().length, jsNumber(m_body->parameters().size()), ReadOnly | DontDelete | DontEnum);
- return func;
-}
-
-JSValue* FuncDeclNode::execute(ExecState* exec)
-{
- return exec->setNormalCompletion();
+ return dst;
}
// ------------------------------ FuncExprNode ---------------------------------
-// ECMA 13
-void FuncExprNode::addParams()
+RegisterID* FuncExprNode::emitCode(CodeGenerator& generator, RegisterID* dst)
{
- for (ParameterNode* p = m_parameter.get(); p; p = p->nextParam())
- m_body->parameters().append(p->ident());
+ return generator.emitNewFunctionExpression(generator.finalDestination(dst), this);
}
-JSValue* FuncExprNode::evaluate(ExecState* exec)
+JSFunction* FuncExprNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain)
{
- 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);
- }
+ JSFunction* func = new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain);
- 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, ReadOnly | DontDelete | DontEnum);
- func->putDirect(exec->propertyNames().prototype, proto, Internal | DontDelete);
+ /*
+ The Identifier in a FunctionExpression can be referenced from inside
+ the FunctionExpression's FunctionBody to allow the function to call
+ itself recursively. However, unlike in a FunctionDeclaration, the
+ Identifier in a FunctionExpression cannot be referenced from and
+ does not affect the scope enclosing the FunctionExpression.
+ */
- if (named) {
- functionScopeObject->putDirect(m_ident, func, Internal | ReadOnly | (exec->codeType() == EvalCode ? 0 : DontDelete));
- exec->popScope();
+ if (!m_ident.isNull()) {
+ JSStaticScopeObject* functionScopeObject = new (exec) JSStaticScopeObject(exec, m_ident, func, ReadOnly | DontDelete);
+ func->scope().push(functionScopeObject);
}
return func;
}
-} // namespace KJS
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/nodes.h b/JavaScriptCore/kjs/nodes.h
index 11cf199..a70d350 100644
--- a/JavaScriptCore/kjs/nodes.h
+++ b/JavaScriptCore/kjs/nodes.h
@@ -26,28 +26,51 @@
#ifndef NODES_H_
#define NODES_H_
-#include "internal.h"
-#include "regexp.h"
+#include "Error.h"
+#include "JSString.h"
+#include "JSType.h"
+#include "Opcode.h"
+#include "RegisterID.h"
+#include "ResultType.h"
+#include "SourceCode.h"
#include "SymbolTable.h"
+#include "regexp.h"
#include <wtf/ListRefPtr.h>
#include <wtf/MathExtras.h>
#include <wtf/OwnPtr.h>
+#include <wtf/UnusedParam.h>
#include <wtf/Vector.h>
#if PLATFORM(X86) && COMPILER(GCC)
-#define KJS_FAST_CALL __attribute__((regparm(3)))
+#define JSC_FAST_CALL __attribute__((regparm(3)))
#else
-#define KJS_FAST_CALL
+#define JSC_FAST_CALL
#endif
-namespace KJS {
+namespace JSC {
- class ConstDeclNode;
+ class CodeBlock;
+ class CodeGenerator;
class FuncDeclNode;
class Node;
+ class EvalCodeBlock;
+ class JSFunction;
+ class ProgramCodeBlock;
class PropertyListNode;
class SourceStream;
+ typedef unsigned int CodeFeatures;
+
+ const CodeFeatures NoFeatures = 0;
+ const CodeFeatures EvalFeature = 1 << 0;
+ const CodeFeatures ClosureFeature = 1 << 1;
+ const CodeFeatures AssignFeature = 1 << 2;
+ const CodeFeatures ArgumentsFeature = 1 << 3;
+ const CodeFeatures WithFeature = 1 << 4;
+ const CodeFeatures CatchFeature = 1 << 5;
+ const CodeFeatures ThisFeature = 1 << 6;
+ const CodeFeatures AllFeatures = EvalFeature | ClosureFeature | AssignFeature | ArgumentsFeature | WithFeature | CatchFeature | ThisFeature;
+
enum Operator {
OpEqual,
OpPlusEq,
@@ -62,7 +85,12 @@ namespace KJS {
OpModEq,
OpLShift,
OpRShift,
- OpURShift,
+ OpURShift
+ };
+
+ enum LogicalOperator {
+ OpLogicalAnd,
+ OpLogicalOr
};
enum Precedence {
@@ -72,7 +100,7 @@ namespace KJS {
PrecLeftHandSide,
PrecPostfix,
PrecUnary,
- PrecMultiplicitave,
+ PrecMultiplicative,
PrecAdditive,
PrecShift,
PrecRelational,
@@ -87,39 +115,31 @@ namespace KJS {
PrecExpression
};
- struct DeclarationStacks {
+ namespace DeclarationStacks {
typedef Vector<Node*, 16> NodeStack;
- enum { IsConstant = 1, HasInitializer = 2 } VarAttrs;
+ enum VarAttrs { IsConstant = 1, HasInitializer = 2 };
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)
- {
- }
+ typedef Vector<RefPtr<FuncDeclNode>, 16> FunctionStack;
+ }
- ExecState* exec;
- NodeStack& nodeStack;
- VarStack& varStack;
- FunctionStack& functionStack;
+ struct SwitchInfo {
+ enum SwitchType { SwitchNone, SwitchImmediate, SwitchCharacter, SwitchString };
+ uint32_t opcodeOffset;
+ SwitchType switchType;
};
class ParserRefCounted : Noncopyable {
protected:
- ParserRefCounted() KJS_FAST_CALL;
- ParserRefCounted(PlacementNewAdoptType) KJS_FAST_CALL
- {
- }
+ ParserRefCounted(JSGlobalData*) JSC_FAST_CALL;
+
+ JSGlobalData* m_globalData;
public:
- void ref() KJS_FAST_CALL;
- void deref() KJS_FAST_CALL;
- unsigned refcount() KJS_FAST_CALL;
+ void ref() JSC_FAST_CALL;
+ void deref() JSC_FAST_CALL;
+ bool hasOneRef() JSC_FAST_CALL;
- static void deleteNewObjects() KJS_FAST_CALL;
+ static void deleteNewObjects(JSGlobalData*) JSC_FAST_CALL;
virtual ~ParserRefCounted();
};
@@ -130,96 +150,91 @@ namespace KJS {
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; }
+ Node(JSGlobalData*) JSC_FAST_CALL;
- // 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 { }
+ /*
+ Return value: The register holding the production's value.
+ dst: An optional parameter specifying the most efficient
+ destination at which to store the production's value.
+ The callee must honor dst.
- protected:
- Node(JSType) KJS_FAST_CALL; // used by ExpressionNode
+ dst provides for a crude form of copy propagation. For example,
- // 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;
+ x = 1
- // 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;
+ becomes
+
+ load r[x], 1
+
+ instead of
- JSValue* throwUndefinedVariableError(ExecState*, const Identifier&) KJS_FAST_CALL;
+ load r0, 1
+ mov r[x], r0
+
+ because the assignment node, "x =", passes r[x] as dst to the number
+ node, "1".
+ */
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* dst = 0) JSC_FAST_CALL
+ {
+ ASSERT_WITH_MESSAGE(0, "Don't know how to generate code for:\n%s\n", toString().ascii());
+ UNUSED_PARAM(dst);
+ return 0;
+ } // FIXME: Make this pure virtual.
- void handleException(ExecState*) KJS_FAST_CALL;
- void handleException(ExecState*, JSValue*) KJS_FAST_CALL;
+ UString toString() const JSC_FAST_CALL;
+ int lineNo() const { return m_line; }
- // for use in execute()
- JSValue* rethrowException(ExecState*) KJS_FAST_CALL;
+ virtual bool isReturnNode() const JSC_FAST_CALL { return false; }
- int m_line : 28;
- unsigned m_expectedReturnType : 3; // JSType
+ // Serialization.
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL = 0;
+ virtual Precedence precedence() const = 0;
+ virtual bool needsParensIfLeftmost() const { return false; }
+
+ protected:
+ int m_line;
};
class ExpressionNode : public Node {
public:
- ExpressionNode() KJS_FAST_CALL : Node() {}
- ExpressionNode(JSType expectedReturn) KJS_FAST_CALL
- : Node(expectedReturn)
+ ExpressionNode(JSGlobalData* globalData, ResultType resultDesc = ResultType::unknown()) JSC_FAST_CALL
+ : Node(globalData)
+ , m_resultDesc(resultDesc)
{
}
- // Special constructor for cases where we overwrite an object in place.
- ExpressionNode(PlacementNewAdoptType) KJS_FAST_CALL
- : Node(PlacementNewAdopt)
- {
- }
+ virtual bool isNumber() const JSC_FAST_CALL { return false; }
+ virtual bool isString() const JSC_FAST_CALL { return false; }
+ virtual bool isNull() const JSC_FAST_CALL { return false; }
+ virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL { return false; }
+ virtual bool isLocation() const JSC_FAST_CALL { return false; }
+ virtual bool isResolveNode() const JSC_FAST_CALL { return false; }
+ virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return false; }
+ virtual bool isDotAccessorNode() const JSC_FAST_CALL { return false; }
- 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; }
+ virtual ExpressionNode* stripUnaryPlus() { return this; }
- JSType expectedReturnType() const KJS_FAST_CALL { return static_cast<JSType>(m_expectedReturnType); }
+ ResultType resultDescriptor() const JSC_FAST_CALL { return m_resultDesc; }
- 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;
+ // This needs to be in public in order to compile using GCC 3.x
+ typedef enum { EvalOperator, FunctionCall } CallerType;
- // Used to optimize those nodes that do extra work when returning a result, even if the result has no semantic relevance
- virtual void optimizeForUnnecessaryResult() { }
+ private:
+ ResultType m_resultDesc;
};
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;
- void pushLabel(const Identifier& ident) KJS_FAST_CALL { m_labelStack.push(ident); }
+ StatementNode(JSGlobalData*) JSC_FAST_CALL;
+ void setLoc(int line0, int line1) JSC_FAST_CALL;
+ int firstLine() const JSC_FAST_CALL { return lineNo(); }
+ int lastLine() const JSC_FAST_CALL { return m_lastLine; }
+
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
- virtual bool isEmptyStatement() const KJS_FAST_CALL { return false; }
+ virtual bool isEmptyStatement() const JSC_FAST_CALL { return false; }
- protected:
- LabelStack m_labelStack;
+ virtual bool isBlock() const JSC_FAST_CALL { return false; }
+ virtual bool isLoop() const JSC_FAST_CALL { return false; }
private:
int m_lastLine;
@@ -227,68 +242,54 @@ namespace KJS {
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)
+ NullNode(JSGlobalData* globalData) JSC_FAST_CALL
+ : ExpressionNode(globalData, ResultType::nullType())
{
}
- 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; }
- };
+ virtual bool isNull() const JSC_FAST_CALL { return true; }
- class TrueNode : public ExpressionNode {
- public:
- TrueNode() KJS_FAST_CALL
- : ExpressionNode(BooleanType)
- {
- }
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
- 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 void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecPrimary; }
};
- class PlaceholderTrueNode : public TrueNode {
+ class BooleanNode : public ExpressionNode {
public:
- // Like TrueNode, but does not serialize as "true".
- PlaceholderTrueNode() KJS_FAST_CALL
- : TrueNode()
+ BooleanNode(JSGlobalData* globalData, bool value) JSC_FAST_CALL
+ : ExpressionNode(globalData, ResultType::boolean())
+ , m_value(value)
{
}
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL { return true; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+
+ protected:
+ bool m_value;
};
class NumberNode : public ExpressionNode {
public:
- NumberNode(double v) KJS_FAST_CALL
- : ExpressionNode(NumberType)
+ NumberNode(JSGlobalData* globalData, double v) JSC_FAST_CALL
+ : ExpressionNode(globalData, ResultType::constNumber())
, 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_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; }
+ virtual bool isNumber() const JSC_FAST_CALL { return true; }
+ virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL { return true; }
+ double value() const JSC_FAST_CALL { return m_double; }
+ virtual void setValue(double d) JSC_FAST_CALL { m_double = d; }
protected:
double m_double;
@@ -296,18 +297,14 @@ namespace KJS {
class ImmediateNumberNode : public NumberNode {
public:
- ImmediateNumberNode(JSValue* v, double d) KJS_FAST_CALL
- : NumberNode(d)
+ ImmediateNumberNode(JSGlobalData* globalData, JSValue* v, double d) JSC_FAST_CALL
+ : NumberNode(globalData, 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); }
+ virtual void setValue(double d) JSC_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
@@ -315,127 +312,201 @@ namespace KJS {
class StringNode : public ExpressionNode {
public:
- StringNode(const UString* v) KJS_FAST_CALL
- : ExpressionNode(StringType)
- , m_value(*v)
+ StringNode(JSGlobalData* globalData, const Identifier& v) JSC_FAST_CALL
+ : ExpressionNode(globalData, ResultType::string())
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual bool isString() const JSC_FAST_CALL { return true; }
+ const Identifier& value() { return m_value; }
+ virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL { return true; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecPrimary; }
private:
- UString m_value;
+ Identifier m_value;
};
-
- class RegExpNode : public ExpressionNode {
+
+ class ThrowableExpressionData {
public:
- RegExpNode(const UString& pattern, const UString& flags) KJS_FAST_CALL
- : m_regExp(new RegExp(pattern, flags))
+ ThrowableExpressionData()
+ : m_divot(static_cast<uint32_t>(-1))
+ , m_startOffset(static_cast<uint16_t>(-1))
+ , m_endOffset(static_cast<uint16_t>(-1))
+ {
+ }
+
+ ThrowableExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset)
+ : m_divot(divot)
+ , m_startOffset(startOffset)
+ , m_endOffset(endOffset)
+ {
+ }
+
+ void setExceptionSourceCode(unsigned divot, unsigned startOffset, unsigned endOffset)
{
+ m_divot = divot;
+ m_startOffset = startOffset;
+ m_endOffset = endOffset;
}
- JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
- virtual Precedence precedence() const { return PrecPrimary; }
+ uint32_t divot() const { return m_divot; }
+ uint16_t startOffset() const { return m_startOffset; }
+ uint16_t endOffset() const { return m_endOffset; }
- private:
- RefPtr<RegExp> m_regExp;
+ protected:
+ RegisterID* emitThrowError(CodeGenerator&, ErrorType, const char* msg);
+ RegisterID* emitThrowError(CodeGenerator&, ErrorType, const char* msg, const Identifier&);
+ uint32_t m_divot;
+ uint16_t m_startOffset;
+ uint16_t m_endOffset;
};
- class ThisNode : public ExpressionNode {
+ class ThrowableSubExpressionData : public ThrowableExpressionData {
public:
- ThisNode() KJS_FAST_CALL
+ ThrowableSubExpressionData()
+ : ThrowableExpressionData()
+ , m_subexpressionDivotOffset(0)
+ , m_subexpressionEndOffset(0)
{
}
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
- virtual Precedence precedence() const { return PrecPrimary; }
- };
+ ThrowableSubExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_subexpressionDivotOffset(0)
+ , m_subexpressionEndOffset(0)
+ {
+ }
- class ResolveNode : public ExpressionNode {
+ void setSubexpressionInfo(uint32_t subexpressionDivot, uint16_t subexpressionOffset) {
+ ASSERT(subexpressionDivot <= m_divot);
+ if ((m_divot - subexpressionDivot) & ~0xFFFF) // Overflow means we can't do this safely, so just point at the primary divot
+ return;
+ m_subexpressionDivotOffset = m_divot - subexpressionDivot;
+ m_subexpressionEndOffset = subexpressionOffset;
+ }
+
+ protected:
+ uint16_t m_subexpressionDivotOffset;
+ uint16_t m_subexpressionEndOffset;
+ };
+
+ class ThrowablePrefixedSubExpressionData : public ThrowableExpressionData {
public:
- ResolveNode(const Identifier& ident) KJS_FAST_CALL
- : m_ident(ident)
+ ThrowablePrefixedSubExpressionData()
+ : ThrowableExpressionData()
+ , m_subexpressionDivotOffset(0)
+ , m_subexpressionStartOffset(0)
{
}
- // Special constructor for cases where we overwrite an object in place.
- ResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
- : ExpressionNode(PlacementNewAdopt)
- , m_ident(PlacementNewAdopt)
+ ThrowablePrefixedSubExpressionData(unsigned divot, unsigned startOffset, unsigned endOffset)
+ : ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_subexpressionDivotOffset(0)
+ , m_subexpressionStartOffset(0)
+ {
+ }
+
+ void setSubexpressionInfo(uint32_t subexpressionDivot, uint16_t subexpressionOffset) {
+ ASSERT(subexpressionDivot >= m_divot);
+ if ((subexpressionDivot - m_divot) & ~0xFFFF) // Overflow means we can't do this safely, so just point at the primary divot
+ return;
+ m_subexpressionDivotOffset = subexpressionDivot - m_divot;
+ m_subexpressionStartOffset = subexpressionOffset;
+ }
+
+ protected:
+ uint16_t m_subexpressionDivotOffset;
+ uint16_t m_subexpressionStartOffset;
+ };
+
+ class RegExpNode : public ExpressionNode, public ThrowableExpressionData {
+ public:
+ RegExpNode(JSGlobalData* globalData, const UString& pattern, const UString& flags) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , m_pattern(pattern)
+ , m_flags(flags)
{
}
- virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_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 void streamTo(SourceStream&) const JSC_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; }
+ private:
+ UString m_pattern;
+ UString m_flags;
+ };
- protected:
- ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
- Identifier m_ident;
- size_t m_index; // Used by LocalVarAccessNode.
+ class ThisNode : public ExpressionNode {
+ public:
+ ThisNode(JSGlobalData* globalData) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ {
+ }
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
};
- class LocalVarAccessNode : public ResolveNode {
+ class ResolveNode : public ExpressionNode {
public:
- // Overwrites a ResolveNode in place.
- LocalVarAccessNode(size_t i) KJS_FAST_CALL
- : ResolveNode(PlacementNewAdopt)
+ ResolveNode(JSGlobalData* globalData, const Identifier& ident, int startOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , m_ident(ident)
+ , m_startOffset(startOffset)
{
- 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
- private:
- ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecPrimary; }
+
+ virtual bool isPure(CodeGenerator&) const JSC_FAST_CALL;
+ virtual bool isLocation() const JSC_FAST_CALL { return true; }
+ virtual bool isResolveNode() const JSC_FAST_CALL { return true; }
+ const Identifier& identifier() const JSC_FAST_CALL { return m_ident; }
+
+ protected:
+ Identifier m_ident;
+ int32_t m_startOffset;
+
};
class ElementNode : public Node {
public:
- ElementNode(int elision, ExpressionNode* node) KJS_FAST_CALL
- : m_elision(elision)
+ ElementNode(JSGlobalData* globalData, int elision, ExpressionNode* node) JSC_FAST_CALL
+ : Node(globalData)
+ , m_elision(elision)
, m_node(node)
{
}
- ElementNode(ElementNode* l, int elision, ExpressionNode* node) KJS_FAST_CALL
- : m_elision(elision)
+ ElementNode(JSGlobalData* globalData, ElementNode* l, int elision, ExpressionNode* node) JSC_FAST_CALL
+ : Node(globalData)
+ , 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;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
- PassRefPtr<ElementNode> releaseNext() KJS_FAST_CALL { return m_next.release(); }
+ int elision() const { return m_elision; }
+ ExpressionNode* value() { return m_node.get(); }
- JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ ElementNode* next() { return m_next.get(); }
+ PassRefPtr<ElementNode> releaseNext() JSC_FAST_CALL { return m_next.release(); }
private:
- friend class ArrayNode;
ListRefPtr<ElementNode> m_next;
int m_elision;
RefPtr<ExpressionNode> m_node;
@@ -443,29 +514,32 @@ namespace KJS {
class ArrayNode : public ExpressionNode {
public:
- ArrayNode(int elision) KJS_FAST_CALL
- : m_elision(elision)
+ ArrayNode(JSGlobalData* globalData, int elision) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , m_elision(elision)
, m_optional(true)
{
}
- ArrayNode(ElementNode* element) KJS_FAST_CALL
- : m_element(element)
+ ArrayNode(JSGlobalData* globalData, ElementNode* element) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , m_element(element)
, m_elision(0)
, m_optional(false)
{
}
- ArrayNode(int elision, ElementNode* element) KJS_FAST_CALL
- : m_element(element)
+ ArrayNode(JSGlobalData* globalData, int elision, ElementNode* element) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecPrimary; }
private:
@@ -478,18 +552,17 @@ namespace KJS {
public:
enum Type { Constant, Getter, Setter };
- PropertyNode(const Identifier& name, ExpressionNode* assign, Type type) KJS_FAST_CALL
- : m_name(name)
+ PropertyNode(JSGlobalData* globalData, const Identifier& name, ExpressionNode* assign, Type type) JSC_FAST_CALL
+ : Node(globalData)
+ , 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 void streamTo(SourceStream&) const JSC_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:
@@ -501,23 +574,24 @@ namespace KJS {
class PropertyListNode : public Node {
public:
- PropertyListNode(PropertyNode* node) KJS_FAST_CALL
- : m_node(node)
+ PropertyListNode(JSGlobalData* globalData, PropertyNode* node) JSC_FAST_CALL
+ : Node(globalData)
+ , m_node(node)
{
}
- PropertyListNode(PropertyNode* node, PropertyListNode* list) KJS_FAST_CALL
- : m_node(node)
+ PropertyListNode(JSGlobalData* globalData, PropertyNode* node, PropertyListNode* list) JSC_FAST_CALL
+ : Node(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_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(); }
+ PassRefPtr<PropertyListNode> releaseNext() JSC_FAST_CALL { return m_next.release(); }
private:
friend class ObjectLiteralNode;
@@ -527,240 +601,215 @@ namespace KJS {
class ObjectLiteralNode : public ExpressionNode {
public:
- ObjectLiteralNode() KJS_FAST_CALL
+ ObjectLiteralNode(JSGlobalData* globalData) JSC_FAST_CALL
+ : ExpressionNode(globalData)
{
}
- ObjectLiteralNode(PropertyListNode* list) KJS_FAST_CALL
- : m_list(list)
+ ObjectLiteralNode(JSGlobalData* globalData, PropertyListNode* list) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecPrimary; }
virtual bool needsParensIfLeftmost() const { return true; }
private:
RefPtr<PropertyListNode> m_list;
};
-
- class BracketAccessorNode : public ExpressionNode {
+
+ class BracketAccessorNode : public ExpressionNode, public ThrowableExpressionData {
public:
- BracketAccessorNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
- : m_base(base)
+ BracketAccessorNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, bool subscriptHasAssignments) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , m_base(base)
, m_subscript(subscript)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
{
}
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_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(); }
+ virtual bool isLocation() const JSC_FAST_CALL { return true; }
+ virtual bool isBracketAccessorNode() const JSC_FAST_CALL { return true; }
+ ExpressionNode* base() JSC_FAST_CALL { return m_base.get(); }
+ ExpressionNode* subscript() JSC_FAST_CALL { return m_subscript.get(); }
private:
- ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
-
RefPtr<ExpressionNode> m_base;
RefPtr<ExpressionNode> m_subscript;
+ bool m_subscriptHasAssignments;
};
- class DotAccessorNode : public ExpressionNode {
+ class DotAccessorNode : public ExpressionNode, public ThrowableExpressionData {
public:
- DotAccessorNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
- : m_base(base)
+ DotAccessorNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_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; }
+ virtual bool isLocation() const JSC_FAST_CALL { return true; }
+ virtual bool isDotAccessorNode() const JSC_FAST_CALL { return true; }
+ ExpressionNode* base() const JSC_FAST_CALL { return m_base.get(); }
+ const Identifier& identifier() const JSC_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(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : Node(globalData)
+ , m_expr(expr)
{
}
- ArgumentListNode(ArgumentListNode* listNode, ExpressionNode* expr) KJS_FAST_CALL
- : m_expr(expr)
+ ArgumentListNode(JSGlobalData* globalData, ArgumentListNode* listNode, ExpressionNode* expr) JSC_FAST_CALL
+ : Node(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_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(); }
+ PassRefPtr<ArgumentListNode> releaseNext() JSC_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(JSGlobalData* globalData) JSC_FAST_CALL
+ : Node(globalData)
{
}
- ArgumentsNode(ArgumentListNode* listNode) KJS_FAST_CALL
- : m_listNode(listNode)
+ ArgumentsNode(JSGlobalData* globalData, ArgumentListNode* listNode) JSC_FAST_CALL
+ : Node(globalData)
+ , m_listNode(listNode)
{
}
- virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class NewExprNode : public ExpressionNode, public ThrowableExpressionData {
public:
- NewExprNode(ExpressionNode* expr) KJS_FAST_CALL
- : m_expr(expr)
+ NewExprNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , m_expr(expr)
{
}
- NewExprNode(ExpressionNode* expr, ArgumentsNode* args) KJS_FAST_CALL
- : m_expr(expr)
+ NewExprNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class EvalFunctionCallNode : public ExpressionNode, public ThrowableExpressionData {
public:
- FunctionCallValueNode(ExpressionNode* expr, ArgumentsNode* args) KJS_FAST_CALL
- : m_expr(expr)
+ EvalFunctionCallNode(JSGlobalData* globalData, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
, 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecCall; }
private:
- RefPtr<ExpressionNode> m_expr;
RefPtr<ArgumentsNode> m_args;
};
- class FunctionCallResolveNode : public ExpressionNode {
+ class FunctionCallValueNode : public ExpressionNode, public ThrowableExpressionData {
public:
- FunctionCallResolveNode(const Identifier& ident, ArgumentsNode* args) KJS_FAST_CALL
- : m_ident(ident)
+ FunctionCallValueNode(JSGlobalData* globalData, ExpressionNode* expr, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_expr(expr)
, 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecCall; }
- protected:
- ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
-
- Identifier m_ident;
+ private:
+ RefPtr<ExpressionNode> m_expr;
RefPtr<ArgumentsNode> m_args;
- size_t m_index; // Used by LocalVarFunctionCallNode.
};
- class LocalVarFunctionCallNode : public FunctionCallResolveNode {
+ class FunctionCallResolveNode : public ExpressionNode, public ThrowableExpressionData {
public:
- LocalVarFunctionCallNode(size_t i) KJS_FAST_CALL
- : FunctionCallResolveNode(PlacementNewAdopt)
+ FunctionCallResolveNode(JSGlobalData* globalData, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
+ , m_args(args)
{
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
- private:
- ALWAYS_INLINE JSValue* inlineEvaluate(ExecState*);
- };
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecCall; }
- class FunctionCallBracketNode : public ExpressionNode {
+ protected:
+ Identifier m_ident;
+ RefPtr<ArgumentsNode> m_args;
+ size_t m_index; // Used by LocalVarFunctionCallNode.
+ size_t m_scopeDepth; // Used by ScopedVarFunctionCallNode and NonLocalVarFunctionCallNode
+ };
+
+ class FunctionCallBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
public:
- FunctionCallBracketNode(ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args) KJS_FAST_CALL
- : m_base(base)
+ FunctionCallBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecCall; }
protected:
@@ -769,232 +818,110 @@ namespace KJS {
RefPtr<ArgumentsNode> m_args;
};
- class FunctionCallDotNode : public ExpressionNode {
+ class FunctionCallDotNode : public ExpressionNode, public ThrowableSubExpressionData {
public:
- FunctionCallDotNode(ExpressionNode* base, const Identifier& ident, ArgumentsNode* args) KJS_FAST_CALL
- : m_base(base)
+ FunctionCallDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ArgumentsNode* args, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class PrePostResolveNode : public ExpressionNode, public ThrowableExpressionData {
public:
- PrePostResolveNode(const Identifier& ident) KJS_FAST_CALL
- : ExpressionNode(NumberType)
+ PrePostResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData, ResultType::constNumber()) // could be reusable for pre?
+ , ThrowableExpressionData(divot, startOffset, endOffset)
, 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 {
+ class PostfixResolveNode : public PrePostResolveNode {
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)
+ PostfixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset)
+ , m_operator(oper)
{
}
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_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;
+ protected:
+ Operator m_operator;
};
- class PostfixBracketNode : public ExpressionNode {
+ class PostfixBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
public:
- PostfixBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
- : m_base(base)
+ PostfixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
, m_subscript(subscript)
+ , m_operator(oper)
{
}
- virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecPostfix; }
protected:
RefPtr<ExpressionNode> m_base;
RefPtr<ExpressionNode> m_subscript;
+ Operator m_operator;
};
- 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 {
+ class PostfixDotNode : public ExpressionNode, public ThrowableSubExpressionData {
public:
- PostfixDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
- : m_base(base)
+ PostfixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
, m_ident(ident)
+ , m_operator(oper)
{
}
- virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecPostfix; }
protected:
RefPtr<ExpressionNode> m_base;
Identifier m_ident;
+ Operator m_operator;
};
- 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 {
+ class PostfixErrorNode : public ExpressionNode, public ThrowableSubExpressionData {
public:
- PostfixErrorNode(ExpressionNode* expr, Operator oper) KJS_FAST_CALL
- : m_expr(expr)
+ PostfixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_expr(expr)
, m_operator(oper)
{
}
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecPostfix; }
private:
@@ -1002,49 +929,37 @@ namespace KJS {
Operator m_operator;
};
- class DeleteResolveNode : public ExpressionNode {
+ class DeleteResolveNode : public ExpressionNode, public ThrowableExpressionData {
public:
- DeleteResolveNode(const Identifier& ident) KJS_FAST_CALL
- : m_ident(ident)
+ DeleteResolveNode(JSGlobalData* globalData, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
{
}
- DeleteResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
- : ExpressionNode(PlacementNewAdopt)
- , m_ident(PlacementNewAdopt)
- {
- }
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
- 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 void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }
private:
Identifier m_ident;
};
- class LocalVarDeleteNode : public DeleteResolveNode {
+ class DeleteBracketNode : public ExpressionNode, public ThrowableExpressionData {
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)
+ DeleteBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }
private:
@@ -1052,17 +967,19 @@ namespace KJS {
RefPtr<ExpressionNode> m_subscript;
};
- class DeleteDotNode : public ExpressionNode {
+ class DeleteDotNode : public ExpressionNode, public ThrowableExpressionData {
public:
- DeleteDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
- : m_base(base)
+ DeleteDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }
private:
@@ -1072,14 +989,15 @@ namespace KJS {
class DeleteValueNode : public ExpressionNode {
public:
- DeleteValueNode(ExpressionNode* expr) KJS_FAST_CALL
- : m_expr(expr)
+ DeleteValueNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }
private:
@@ -1088,14 +1006,15 @@ namespace KJS {
class VoidNode : public ExpressionNode {
public:
- VoidNode(ExpressionNode* expr) KJS_FAST_CALL
- : m_expr(expr)
+ VoidNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }
private:
@@ -1104,234 +1023,112 @@ namespace KJS {
class TypeOfResolveNode : public ExpressionNode {
public:
- TypeOfResolveNode(const Identifier& ident) KJS_FAST_CALL
- : ExpressionNode(StringType)
+ TypeOfResolveNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL
+ : ExpressionNode(globalData, ResultType::string())
, 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }
- const Identifier& identifier() const KJS_FAST_CALL { return m_ident; }
+ const Identifier& identifier() const JSC_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)
+ TypeOfValueNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : ExpressionNode(globalData, ResultType::string())
, 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class PrefixResolveNode : public PrePostResolveNode {
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)
+ PrefixResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : PrePostResolveNode(globalData, ident, divot, startOffset, endOffset)
+ , m_operator(oper)
{
}
- virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_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;
+ protected:
+ Operator m_operator;
};
- class PrefixBracketNode : public ExpressionNode {
+ class PrefixBracketNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData {
public:
- PrefixBracketNode(ExpressionNode* base, ExpressionNode* subscript) KJS_FAST_CALL
- : m_base(base)
+ PrefixBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
, m_subscript(subscript)
+ , m_operator(oper)
{
}
- virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }
protected:
RefPtr<ExpressionNode> m_base;
RefPtr<ExpressionNode> m_subscript;
+ Operator m_operator;
};
- 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 {
+ class PrefixDotNode : public ExpressionNode, public ThrowablePrefixedSubExpressionData {
public:
- PrefixDotNode(ExpressionNode* base, const Identifier& ident) KJS_FAST_CALL
- : m_base(base)
+ PrefixDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowablePrefixedSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
, m_ident(ident)
+ , m_operator(oper)
{
}
- virtual void optimizeVariableAccess(const SymbolTable&, const LocalStorage&, NodeStack&) KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecPostfix; }
protected:
RefPtr<ExpressionNode> m_base;
Identifier m_ident;
+ Operator m_operator;
};
- 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 {
+ class PrefixErrorNode : public ExpressionNode, public ThrowableExpressionData {
public:
- PrefixErrorNode(ExpressionNode* expr, Operator oper) KJS_FAST_CALL
- : m_expr(expr)
+ PrefixErrorNode(JSGlobalData* globalData, ExpressionNode* expr, Operator oper, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_expr(expr)
, m_operator(oper)
{
}
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }
private:
@@ -1339,693 +1136,421 @@ namespace KJS {
Operator m_operator;
};
- class UnaryPlusNode : public ExpressionNode {
+ class UnaryOpNode : public ExpressionNode {
public:
- UnaryPlusNode(ExpressionNode* expr) KJS_FAST_CALL
- : ExpressionNode(NumberType)
+ UnaryOpNode(JSGlobalData* globalData, ExpressionNode* expr)
+ : ExpressionNode(globalData)
, 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)
+ UnaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr)
+ : ExpressionNode(globalData, type)
, 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; }
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual OpcodeID opcode() const JSC_FAST_CALL = 0;
- private:
+ protected:
RefPtr<ExpressionNode> m_expr;
};
- class BitwiseNotNode : public ExpressionNode {
+ class UnaryPlusNode : public UnaryOpNode {
public:
- BitwiseNotNode(ExpressionNode* expr) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_expr(expr)
+ UnaryPlusNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : UnaryOpNode(globalData, ResultType::constNumber(), 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*);
+ virtual ExpressionNode* stripUnaryPlus() { return m_expr.get(); }
- RefPtr<ExpressionNode> m_expr;
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_to_jsnumber; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
};
- class LogicalNotNode : public ExpressionNode {
+ class NegateNode : public UnaryOpNode {
public:
- LogicalNotNode(ExpressionNode* expr) KJS_FAST_CALL
- : ExpressionNode(BooleanType)
- , m_expr(expr)
+ NegateNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : UnaryOpNode(globalData, ResultType::reusableNumber(), 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 OpcodeID opcode() const JSC_FAST_CALL { return op_negate; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecUnary; }
-
- private:
- RefPtr<ExpressionNode> m_expr;
};
- class MultNode : public ExpressionNode {
+ class BitwiseNotNode : public UnaryOpNode {
public:
- MultNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_term1(term1)
- , m_term2(term2)
+ BitwiseNotNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : UnaryOpNode(globalData, ResultType::reusableNumber(), 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 PrecMultiplicitave; }
-
- private:
- ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
-
- RefPtr<ExpressionNode> m_term1;
- RefPtr<ExpressionNode> m_term2;
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_bitnot; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
};
- class DivNode : public ExpressionNode {
+ class LogicalNotNode : public UnaryOpNode {
public:
- DivNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_term1(term1)
- , m_term2(term2)
+ LogicalNotNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : UnaryOpNode(globalData, ResultType::boolean(), 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 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;
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_not; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecUnary; }
};
- class ModNode : public ExpressionNode {
+ class BinaryOpNode : public ExpressionNode {
public:
- ModNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_term1(term1)
- , m_term2(term2)
+ BinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ExpressionNode(globalData)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_rightHasAssignments(rightHasAssignments)
{
}
- 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; }
+ BinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ExpressionNode(globalData, type)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_rightHasAssignments(rightHasAssignments)
+ {
+ }
- private:
- ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual OpcodeID opcode() const JSC_FAST_CALL = 0;
- RefPtr<ExpressionNode> m_term1;
- RefPtr<ExpressionNode> m_term2;
+ protected:
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ bool m_rightHasAssignments;
};
- class AddNode : public ExpressionNode {
+ class ReverseBinaryOpNode : public ExpressionNode {
public:
- AddNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : m_term1(term1)
- , m_term2(term2)
+ ReverseBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ExpressionNode(globalData)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_rightHasAssignments(rightHasAssignments)
{
}
- 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)
+ ReverseBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments)
+ : ExpressionNode(globalData, type)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_rightHasAssignments(rightHasAssignments)
{
}
- RefPtr<ExpressionNode> m_term1;
- RefPtr<ExpressionNode> m_term2;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual OpcodeID opcode() const JSC_FAST_CALL = 0;
- private:
- ALWAYS_INLINE double inlineEvaluateToNumber(ExecState*);
+ protected:
+ RefPtr<ExpressionNode> m_expr1;
+ RefPtr<ExpressionNode> m_expr2;
+ bool m_rightHasAssignments;
};
- class AddNumbersNode : public AddNode {
+ class MultNode : public BinaryOpNode {
public:
- AddNumbersNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : AddNode(term1, term2, NumberType)
+ MultNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- 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;
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_mul; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecMultiplicative; }
};
- class AddStringLeftNode : public AddNode {
+ class DivNode : public BinaryOpNode {
public:
- AddStringLeftNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : AddNode(term1, term2, StringType)
+ DivNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_div; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecMultiplicative; }
};
- class AddStringRightNode : public AddNode {
+ class ModNode : public BinaryOpNode {
public:
- AddStringRightNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : AddNode(term1, term2, StringType)
+ ModNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_mod; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecMultiplicative; }
};
- class AddStringsNode : public AddNode {
+ class AddNode : public BinaryOpNode {
public:
- AddStringsNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : AddNode(term1, term2, StringType)
+ AddNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::forAdd(expr1->resultDescriptor(), expr2->resultDescriptor()), expr1, expr2, rightHasAssignments)
{
}
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_add; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecAdditive; }
};
- class SubNode : public ExpressionNode {
+ class SubNode : public BinaryOpNode {
public:
- SubNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_term1(term1)
- , m_term2(term2)
+ SubNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_sub; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class LeftShiftNode : public BinaryOpNode {
public:
- LeftShiftNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_term1(term1)
- , m_term2(term2)
+ LeftShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_lshift; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class RightShiftNode : public BinaryOpNode {
public:
- RightShiftNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_term1(term1)
- , m_term2(term2)
+ RightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_rshift; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class UnsignedRightShiftNode : public BinaryOpNode {
public:
- UnsignedRightShiftNode(ExpressionNode* term1, ExpressionNode* term2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_term1(term1)
- , m_term2(term2)
+ UnsignedRightShiftNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_urshift; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class LessNode : public BinaryOpNode {
public:
- LessNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(BooleanType)
- , m_expr1(expr1)
- , m_expr2(expr2)
+ LessNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_less; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class GreaterNode : public ReverseBinaryOpNode {
public:
- LessNumbersNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : LessNode(expr1, expr2)
+ GreaterNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : ReverseBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
{
}
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
-
- private:
- ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_less; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecRelational; }
};
- class LessStringsNode : public LessNode {
+ class LessEqNode : public BinaryOpNode {
public:
- LessStringsNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : LessNode(expr1, expr2)
+ LessEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
{
}
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual bool evaluateToBoolean(ExecState*) KJS_FAST_CALL;
-
- private:
- ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_lesseq; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return PrecRelational; }
};
- class GreaterNode : public ExpressionNode {
+ class GreaterEqNode : public ReverseBinaryOpNode {
public:
- GreaterNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : m_expr1(expr1)
- , m_expr2(expr2)
+ GreaterEqNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : ReverseBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_lesseq; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class ThrowableBinaryOpNode : public BinaryOpNode, public ThrowableExpressionData {
public:
- LessEqNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : m_expr1(expr1)
- , m_expr2(expr2)
+ ThrowableBinaryOpNode(JSGlobalData* globalData, ResultType type, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, type, expr1, expr2, rightHasAssignments)
{
}
-
- 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)
+ ThrowableBinaryOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, expr1, expr2, rightHasAssignments)
{
}
-
- 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
};
-
- class InstanceOfNode : public ExpressionNode {
+
+ class InstanceOfNode : public ThrowableBinaryOpNode {
public:
- InstanceOfNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(BooleanType)
- , m_expr1(expr1)
- , m_expr2(expr2)
+ InstanceOfNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : ThrowableBinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_instanceof; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecRelational; }
- private:
- RefPtr<ExpressionNode> m_expr1;
- RefPtr<ExpressionNode> m_expr2;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
};
- class InNode : public ExpressionNode {
+ class InNode : public ThrowableBinaryOpNode {
public:
- InNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : m_expr1(expr1)
- , m_expr2(expr2)
+ InNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : ThrowableBinaryOpNode(globalData, expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_in; }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecRelational; }
-
- private:
- RefPtr<ExpressionNode> m_expr1;
- RefPtr<ExpressionNode> m_expr2;
};
- class EqualNode : public ExpressionNode {
+ class EqualNode : public BinaryOpNode {
public:
- EqualNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(BooleanType)
- , m_expr1(expr1)
- , m_expr2(expr2)
+ EqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
{
}
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_eq; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class NotEqualNode : public BinaryOpNode {
public:
- NotEqualNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(BooleanType)
- , m_expr1(expr1)
- , m_expr2(expr2)
+ NotEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_neq; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class StrictEqualNode : public BinaryOpNode {
public:
- StrictEqualNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(BooleanType)
- , m_expr1(expr1)
- , m_expr2(expr2)
+ StrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
{
}
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual OpcodeID opcode() const JSC_FAST_CALL { return op_stricteq; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class NotStrictEqualNode : public BinaryOpNode {
public:
- NotStrictEqualNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(BooleanType)
- , m_expr1(expr1)
- , m_expr2(expr2)
+ NotStrictEqualNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::boolean(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_nstricteq; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class BitAndNode : public BinaryOpNode {
public:
- BitAndNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_expr1(expr1)
- , m_expr2(expr2)
+ BitAndNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_bitand; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class BitOrNode : public BinaryOpNode {
public:
- BitOrNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_expr1(expr1)
- , m_expr2(expr2)
+ BitOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_bitor; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class BitXOrNode : public BinaryOpNode {
public:
- BitXOrNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(NumberType)
- , m_expr1(expr1)
- , m_expr2(expr2)
+ BitXOrNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) JSC_FAST_CALL
+ : BinaryOpNode(globalData, ResultType::reusableNumber(), expr1, expr2, rightHasAssignments)
{
}
- 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 OpcodeID opcode() const JSC_FAST_CALL { return op_bitxor; }
+ virtual void streamTo(SourceStream&) const JSC_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 {
+ class LogicalOpNode : public ExpressionNode {
public:
- LogicalOrNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : ExpressionNode(BooleanType)
+ LogicalOpNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, LogicalOperator oper) JSC_FAST_CALL
+ : ExpressionNode(globalData, ResultType::boolean())
, m_expr1(expr1)
, m_expr2(expr2)
+ , m_operator(oper)
{
}
- 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; }
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual Precedence precedence() const { return (m_operator == OpLogicalAnd) ? PrecLogicalAnd : PrecLogicalOr; }
private:
- ALWAYS_INLINE bool inlineEvaluateToBoolean(ExecState*);
-
RefPtr<ExpressionNode> m_expr1;
RefPtr<ExpressionNode> m_expr2;
+ LogicalOperator m_operator;
};
/**
@@ -2033,20 +1558,16 @@ namespace KJS {
*/
class ConditionalNode : public ExpressionNode {
public:
- ConditionalNode(ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : m_logical(logical)
+ ConditionalNode(JSGlobalData* globalData, ExpressionNode* logical, ExpressionNode* expr1, ExpressionNode* expr2) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecConditional; }
private:
@@ -2055,201 +1576,169 @@ namespace KJS {
RefPtr<ExpressionNode> m_expr2;
};
- class ReadModifyResolveNode : public ExpressionNode {
+ class ReadModifyResolveNode : public ExpressionNode, public ThrowableExpressionData {
public:
- ReadModifyResolveNode(const Identifier& ident, Operator oper, ExpressionNode* right) KJS_FAST_CALL
- : m_ident(ident)
- , m_operator(oper)
+ ReadModifyResolveNode(JSGlobalData* globalData, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_ident(ident)
, m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
{
}
- ReadModifyResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
- : ExpressionNode(PlacementNewAdopt)
- , m_ident(PlacementNewAdopt)
- , m_right(PlacementNewAdopt)
- {
- }
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
- 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 void streamTo(SourceStream&) const JSC_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.
+ Operator m_operator : 31;
+ bool m_rightHasAssignments : 1;
};
- 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 {
+ class AssignResolveNode : public ExpressionNode, public ThrowableExpressionData {
public:
- AssignResolveNode(const Identifier& ident, ExpressionNode* right) KJS_FAST_CALL
- : m_ident(ident)
+ AssignResolveNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , m_ident(ident)
, m_right(right)
+ , m_rightHasAssignments(rightHasAssignments)
{
}
- AssignResolveNode(PlacementNewAdoptType) KJS_FAST_CALL
- : ExpressionNode(PlacementNewAdopt)
- , m_ident(PlacementNewAdopt)
- , m_right(PlacementNewAdopt)
- {
- }
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
- 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 void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecAssignment; }
protected:
Identifier m_ident;
RefPtr<ExpressionNode> m_right;
size_t m_index; // Used by ReadModifyLocalVarNode.
+ bool m_rightHasAssignments;
};
- 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 {
+ class ReadModifyBracketNode : public ExpressionNode, public ThrowableSubExpressionData {
public:
- ReadModifyBracketNode(ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right) KJS_FAST_CALL
- : m_base(base)
+ ReadModifyBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, Operator oper, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
, m_subscript(subscript)
- , m_operator(oper)
, m_right(right)
+ , m_operator(oper)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ , m_rightHasAssignments(rightHasAssignments)
{
}
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecAssignment; }
protected:
RefPtr<ExpressionNode> m_base;
RefPtr<ExpressionNode> m_subscript;
- Operator m_operator;
RefPtr<ExpressionNode> m_right;
+ Operator m_operator : 30;
+ bool m_subscriptHasAssignments : 1;
+ bool m_rightHasAssignments : 1;
};
- class AssignBracketNode : public ExpressionNode {
+ class AssignBracketNode : public ExpressionNode, public ThrowableExpressionData {
public:
- AssignBracketNode(ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right) KJS_FAST_CALL
- : m_base(base)
+ AssignBracketNode(JSGlobalData* globalData, ExpressionNode* base, ExpressionNode* subscript, ExpressionNode* right, bool subscriptHasAssignments, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
, m_subscript(subscript)
, m_right(right)
+ , m_subscriptHasAssignments(subscriptHasAssignments)
+ , m_rightHasAssignments(rightHasAssignments)
{
}
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecAssignment; }
protected:
RefPtr<ExpressionNode> m_base;
RefPtr<ExpressionNode> m_subscript;
RefPtr<ExpressionNode> m_right;
+ bool m_subscriptHasAssignments : 1;
+ bool m_rightHasAssignments : 1;
};
- class AssignDotNode : public ExpressionNode {
+ class AssignDotNode : public ExpressionNode, public ThrowableExpressionData {
public:
- AssignDotNode(ExpressionNode* base, const Identifier& ident, ExpressionNode* right) KJS_FAST_CALL
- : m_base(base)
+ AssignDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
, m_ident(ident)
, m_right(right)
+ , m_rightHasAssignments(rightHasAssignments)
{
}
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecAssignment; }
protected:
RefPtr<ExpressionNode> m_base;
Identifier m_ident;
RefPtr<ExpressionNode> m_right;
+ bool m_rightHasAssignments;
};
- class ReadModifyDotNode : public ExpressionNode {
+ class ReadModifyDotNode : public ExpressionNode, public ThrowableSubExpressionData {
public:
- ReadModifyDotNode(ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right) KJS_FAST_CALL
- : m_base(base)
+ ReadModifyDotNode(JSGlobalData* globalData, ExpressionNode* base, const Identifier& ident, Operator oper, ExpressionNode* right, bool rightHasAssignments, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableSubExpressionData(divot, startOffset, endOffset)
+ , m_base(base)
, m_ident(ident)
- , m_operator(oper)
, m_right(right)
+ , m_operator(oper)
+ , m_rightHasAssignments(rightHasAssignments)
{
}
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecAssignment; }
protected:
RefPtr<ExpressionNode> m_base;
Identifier m_ident;
- Operator m_operator;
RefPtr<ExpressionNode> m_right;
+ Operator m_operator : 31;
+ bool m_rightHasAssignments : 1;
};
- class AssignErrorNode : public ExpressionNode {
+ class AssignErrorNode : public ExpressionNode, public ThrowableExpressionData {
public:
- AssignErrorNode(ExpressionNode* left, Operator oper, ExpressionNode* right) KJS_FAST_CALL
- : m_left(left)
+ AssignErrorNode(JSGlobalData* globalData, ExpressionNode* left, Operator oper, ExpressionNode* right, unsigned divot, unsigned startOffset, unsigned endOffset) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , ThrowableExpressionData(divot, startOffset, endOffset)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecAssignment; }
protected:
@@ -2260,16 +1749,15 @@ namespace KJS {
class CommaNode : public ExpressionNode {
public:
- CommaNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : m_expr1(expr1)
+ CommaNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecExpression; }
private:
@@ -2279,8 +1767,8 @@ namespace KJS {
class VarDeclCommaNode : public CommaNode {
public:
- VarDeclCommaNode(ExpressionNode* expr1, ExpressionNode* expr2) KJS_FAST_CALL
- : CommaNode(expr1, expr2)
+ VarDeclCommaNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2) JSC_FAST_CALL
+ : CommaNode(globalData, expr1, expr2)
{
}
virtual Precedence precedence() const { return PrecAssignment; }
@@ -2288,33 +1776,31 @@ namespace KJS {
class ConstDeclNode : public ExpressionNode {
public:
- ConstDeclNode(const Identifier& ident, ExpressionNode* in) KJS_FAST_CALL;
+ ConstDeclNode(JSGlobalData* globalData, const Identifier& ident, ExpressionNode* in) JSC_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 void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
- PassRefPtr<ConstDeclNode> releaseNext() KJS_FAST_CALL { return m_next.release(); }
+ PassRefPtr<ConstDeclNode> releaseNext() JSC_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;
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual RegisterID* emitCodeSingle(CodeGenerator&) JSC_FAST_CALL;
};
class ConstStatementNode : public StatementNode {
public:
- ConstStatementNode(ConstDeclNode* next) KJS_FAST_CALL
- : m_next(next)
+ ConstStatementNode(JSGlobalData* globalData, ConstDeclNode* next) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , 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;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
private:
RefPtr<ConstDeclNode> m_next;
@@ -2324,6 +1810,8 @@ namespace KJS {
class SourceElements : public ParserRefCounted {
public:
+ SourceElements(JSGlobalData* globalData) : ParserRefCounted(globalData) {}
+
void append(PassRefPtr<StatementNode>);
void releaseContentsIntoVector(StatementVector& destination)
{
@@ -2337,37 +1825,53 @@ namespace KJS {
class BlockNode : public StatementNode {
public:
- BlockNode(SourceElements* children) KJS_FAST_CALL;
+ BlockNode(JSGlobalData*, SourceElements* children) JSC_FAST_CALL;
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_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;
+ StatementVector& children() { return m_children; }
+ virtual bool isBlock() const JSC_FAST_CALL { return true; }
protected:
StatementVector m_children;
};
class EmptyStatementNode : public StatementNode {
public:
- EmptyStatementNode() KJS_FAST_CALL // debug
+ EmptyStatementNode(JSGlobalData* globalData) JSC_FAST_CALL // debug
+ : StatementNode(globalData)
{
}
- virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
- virtual bool isEmptyStatement() const KJS_FAST_CALL { return true; }
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual bool isEmptyStatement() const JSC_FAST_CALL { return true; }
+ };
+
+ class DebuggerStatementNode : public StatementNode {
+ public:
+ DebuggerStatementNode(JSGlobalData* globalData) JSC_FAST_CALL
+ : StatementNode(globalData)
+ {
+ }
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
};
class ExprStatementNode : public StatementNode {
public:
- ExprStatementNode(ExpressionNode* expr) KJS_FAST_CALL
- : m_expr(expr)
+ ExprStatementNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
private:
RefPtr<ExpressionNode> m_expr;
@@ -2375,14 +1879,15 @@ namespace KJS {
class VarStatementNode : public StatementNode {
public:
- VarStatementNode(ExpressionNode* expr) KJS_FAST_CALL
- : m_expr(expr)
+ VarStatementNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , m_expr(expr)
{
}
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_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;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
private:
RefPtr<ExpressionNode> m_expr;
@@ -2390,15 +1895,15 @@ namespace KJS {
class IfNode : public StatementNode {
public:
- IfNode(ExpressionNode* condition, StatementNode* ifBlock) KJS_FAST_CALL
- : m_condition(condition)
+ IfNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
protected:
RefPtr<ExpressionNode> m_condition;
@@ -2407,15 +1912,14 @@ namespace KJS {
class IfElseNode : public IfNode {
public:
- IfElseNode(ExpressionNode* condtion, StatementNode* ifBlock, StatementNode* elseBlock) KJS_FAST_CALL
- : IfNode(condtion, ifBlock)
+ IfElseNode(JSGlobalData* globalData, ExpressionNode* condition, StatementNode* ifBlock, StatementNode* elseBlock) JSC_FAST_CALL
+ : IfNode(globalData, condition, 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
private:
RefPtr<StatementNode> m_elseBlock;
@@ -2423,16 +1927,17 @@ namespace KJS {
class DoWhileNode : public StatementNode {
public:
- DoWhileNode(StatementNode* statement, ExpressionNode* expr) KJS_FAST_CALL
- : m_statement(statement)
+ DoWhileNode(JSGlobalData* globalData, StatementNode* statement, ExpressionNode* expr) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual bool isLoop() const JSC_FAST_CALL { return true; }
private:
RefPtr<StatementNode> m_statement;
RefPtr<ExpressionNode> m_expr;
@@ -2440,16 +1945,17 @@ namespace KJS {
class WhileNode : public StatementNode {
public:
- WhileNode(ExpressionNode* expr, StatementNode* statement) KJS_FAST_CALL
- : m_expr(expr)
+ WhileNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual bool isLoop() const JSC_FAST_CALL { return true; }
private:
RefPtr<ExpressionNode> m_expr;
RefPtr<StatementNode> m_statement;
@@ -2457,26 +1963,21 @@ namespace KJS {
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)
+ ForNode(JSGlobalData* globalData, ExpressionNode* expr1, ExpressionNode* expr2, ExpressionNode* expr3, StatementNode* statement, bool expr1WasVarDecl) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , m_expr1(expr1)
+ , m_expr2(expr2)
+ , m_expr3(expr3)
, 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual bool isLoop() const JSC_FAST_CALL { return true; }
private:
RefPtr<ExpressionNode> m_expr1;
RefPtr<ExpressionNode> m_expr2;
@@ -2485,15 +1986,15 @@ namespace KJS {
bool m_expr1WasVarDecl;
};
- class ForInNode : public StatementNode {
+ class ForInNode : public StatementNode, public ThrowableExpressionData {
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;
+ ForInNode(JSGlobalData*, ExpressionNode*, ExpressionNode*, StatementNode*) JSC_FAST_CALL;
+ ForInNode(JSGlobalData*, const Identifier&, ExpressionNode*, ExpressionNode*, StatementNode*, int divot, int startOffset, int endOffset) JSC_FAST_CALL;
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual bool isLoop() const JSC_FAST_CALL { return true; }
private:
Identifier m_ident;
RefPtr<ExpressionNode> m_init;
@@ -2503,52 +2004,57 @@ namespace KJS {
bool m_identIsVarDecl;
};
- class ContinueNode : public StatementNode {
+ class ContinueNode : public StatementNode, public ThrowableExpressionData {
public:
- ContinueNode() KJS_FAST_CALL
+ ContinueNode(JSGlobalData* globalData) JSC_FAST_CALL
+ : StatementNode(globalData)
{
}
- ContinueNode(const Identifier& ident) KJS_FAST_CALL
- : m_ident(ident)
+ ContinueNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , m_ident(ident)
{
}
-
- virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
private:
Identifier m_ident;
};
- class BreakNode : public StatementNode {
+ class BreakNode : public StatementNode, public ThrowableExpressionData {
public:
- BreakNode() KJS_FAST_CALL
+ BreakNode(JSGlobalData* globalData) JSC_FAST_CALL
+ : StatementNode(globalData)
{
}
- BreakNode(const Identifier& ident) KJS_FAST_CALL
- : m_ident(ident)
+ BreakNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , m_ident(ident)
{
}
-
- virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
private:
Identifier m_ident;
};
- class ReturnNode : public StatementNode {
+ class ReturnNode : public StatementNode, public ThrowableExpressionData {
public:
- ReturnNode(ExpressionNode* value) KJS_FAST_CALL
- : m_value(value)
+ ReturnNode(JSGlobalData* globalData, ExpressionNode* value) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ virtual bool isReturnNode() const JSC_FAST_CALL { return true; }
private:
RefPtr<ExpressionNode> m_value;
@@ -2556,48 +2062,52 @@ namespace KJS {
class WithNode : public StatementNode {
public:
- WithNode(ExpressionNode* expr, StatementNode* statement) KJS_FAST_CALL
- : m_expr(expr)
+ WithNode(JSGlobalData* globalData, ExpressionNode* expr, StatementNode* statement, uint32_t divot, uint32_t expressionLength) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , m_expr(expr)
, m_statement(statement)
+ , m_divot(divot)
+ , m_expressionLength(expressionLength)
{
}
- 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
private:
RefPtr<ExpressionNode> m_expr;
RefPtr<StatementNode> m_statement;
+ uint32_t m_divot;
+ uint32_t m_expressionLength;
};
- class LabelNode : public StatementNode {
+ class LabelNode : public StatementNode, public ThrowableExpressionData {
public:
- LabelNode(const Identifier& label, StatementNode* statement) KJS_FAST_CALL
- : m_label(label)
+ LabelNode(JSGlobalData* globalData, const Identifier& name, StatementNode* statement) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , m_name(name)
, 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 RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
private:
- Identifier m_label;
+ Identifier m_name;
RefPtr<StatementNode> m_statement;
};
- class ThrowNode : public StatementNode {
+ class ThrowNode : public StatementNode, public ThrowableExpressionData {
public:
- ThrowNode(ExpressionNode* expr) KJS_FAST_CALL
- : m_expr(expr)
+ ThrowNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
private:
RefPtr<ExpressionNode> m_expr;
@@ -2605,17 +2115,18 @@ namespace KJS {
class TryNode : public StatementNode {
public:
- TryNode(StatementNode* tryBlock, const Identifier& exceptionIdent, StatementNode* catchBlock, StatementNode* finallyBlock) KJS_FAST_CALL
- : m_tryBlock(tryBlock)
+ TryNode(JSGlobalData* globalData, StatementNode* tryBlock, const Identifier& exceptionIdent, StatementNode* catchBlock, StatementNode* finallyBlock) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , 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;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* dst = 0) JSC_FAST_CALL;
private:
RefPtr<StatementNode> m_tryBlock;
@@ -2626,21 +2137,23 @@ namespace KJS {
class ParameterNode : public Node {
public:
- ParameterNode(const Identifier& ident) KJS_FAST_CALL
- : m_ident(ident)
+ ParameterNode(JSGlobalData* globalData, const Identifier& ident) JSC_FAST_CALL
+ : Node(globalData)
+ , m_ident(ident)
{
}
- ParameterNode(ParameterNode* l, const Identifier& ident) KJS_FAST_CALL
- : m_ident(ident)
+ ParameterNode(JSGlobalData* globalData, ParameterNode* l, const Identifier& ident) JSC_FAST_CALL
+ : Node(globalData)
+ , 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(); }
+ Identifier ident() JSC_FAST_CALL { return m_ident; }
+ ParameterNode *nextParam() JSC_FAST_CALL { return m_next.get(); }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ PassRefPtr<ParameterNode> releaseNext() JSC_FAST_CALL { return m_next.release(); }
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
private:
@@ -2652,92 +2165,173 @@ namespace KJS {
class ScopeNode : public BlockNode {
public:
- ScopeNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+ ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+
+ const SourceCode& source() const { return m_source; }
+ const UString& sourceURL() const JSC_FAST_CALL { return m_source.provider()->url(); }
+ intptr_t sourceID() const { return m_source.provider()->asID(); }
- 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;
+ bool usesEval() const { return m_features & EvalFeature; }
+ bool usesArguments() const { return m_features & ArgumentsFeature; }
+ void setUsesArguments() { m_features |= ArgumentsFeature; }
+ bool usesThis() const { return m_features & ThisFeature; }
+ bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); }
+
+ VarStack& varStack() { return m_varStack; }
+ FunctionStack& functionStack() { return m_functionStack; }
+
+ int neededConstants()
+ {
+ // We may need 1 more constant than the count given by the parser,
+ // because of the various uses of jsUndefined().
+ return m_numConstants + 1;
+ }
protected:
- void optimizeVariableAccess(ExecState*) KJS_FAST_CALL;
+ void setSource(const SourceCode& source) { m_source = source; }
VarStack m_varStack;
FunctionStack m_functionStack;
private:
- UString m_sourceURL;
- int m_sourceId;
+ SourceCode m_source;
+ CodeFeatures m_features;
+ int m_numConstants;
};
class ProgramNode : public ScopeNode {
public:
- static ProgramNode* create(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+ static ProgramNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
- virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ ProgramCodeBlock& byteCode(ScopeChainNode* scopeChain) JSC_FAST_CALL
+ {
+ if (!m_code)
+ generateCode(scopeChain);
+ return *m_code;
+ }
private:
- ProgramNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+ ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
- void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
- ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+ void generateCode(ScopeChainNode*) JSC_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_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.)
+
+ OwnPtr<ProgramCodeBlock> m_code;
};
class EvalNode : public ScopeNode {
public:
- static EvalNode* create(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+ static EvalNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
- virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ EvalCodeBlock& byteCode(ScopeChainNode* scopeChain) JSC_FAST_CALL
+ {
+ if (!m_code)
+ generateCode(scopeChain);
+ return *m_code;
+ }
private:
- EvalNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+ EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
- ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+ void generateCode(ScopeChainNode*) JSC_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ OwnPtr<EvalCodeBlock> m_code;
};
class FunctionBodyNode : public ScopeNode {
public:
- static FunctionBodyNode* create(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+ static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
+ static FunctionBodyNode* create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants) JSC_FAST_CALL;
+ ~FunctionBodyNode();
- virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
+ const Identifier* parameters() const JSC_FAST_CALL { return m_parameters; }
+ size_t parameterCount() const { return m_parameterCount; }
+ UString paramString() const JSC_FAST_CALL;
+ Identifier* copyParameters();
- SymbolTable& symbolTable() KJS_FAST_CALL { return m_symbolTable; }
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ SymbolTable& symbolTable() { return m_symbolTable; } // FIXME: Remove this
+
+ CodeBlock& byteCode(ScopeChainNode* scopeChain) JSC_FAST_CALL
+ {
+ ASSERT(scopeChain);
+ if (!m_code)
+ generateCode(scopeChain);
+ return *m_code;
+ }
- Vector<Identifier>& parameters() KJS_FAST_CALL { return m_parameters; }
- UString paramString() const KJS_FAST_CALL;
+ CodeBlock& generatedByteCode() JSC_FAST_CALL
+ {
+ ASSERT(m_code);
+ return *m_code;
+ }
+
+ bool isGenerated() JSC_FAST_CALL
+ {
+ return m_code;
+ }
+
+ void mark();
+
+ void finishParsing(const SourceCode&, ParameterNode*);
+ void finishParsing(Identifier* parameters, size_t parameterCount);
+
+ UString toSourceString() const JSC_FAST_CALL { return UString("{") + source().toString() + UString("}"); }
+
+ // These objects are ref/deref'd a lot in the scope chain, so this is a faster ref/deref.
+ // If the virtual machine changes so this doesn't happen as much we can change back.
+ void ref()
+ {
+ if (++m_refCount == 1)
+ ScopeNode::ref();
+ }
+ void deref()
+ {
+ ASSERT(m_refCount);
+ if (!--m_refCount)
+ ScopeNode::deref();
+ }
protected:
- FunctionBodyNode(SourceElements*, VarStack*, FunctionStack*) KJS_FAST_CALL;
+ FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants) JSC_FAST_CALL;
private:
- void initializeSymbolTable(ExecState*) KJS_FAST_CALL;
- ALWAYS_INLINE void processDeclarations(ExecState*) KJS_FAST_CALL;
+ void generateCode(ScopeChainNode*) JSC_FAST_CALL;
- bool m_initialized;
- Vector<Identifier> m_parameters;
+ Identifier* m_parameters;
+ size_t m_parameterCount;
SymbolTable m_symbolTable;
+ OwnPtr<CodeBlock> m_code;
+ unsigned m_refCount;
};
class FuncExprNode : public ExpressionNode {
public:
- FuncExprNode(const Identifier& ident, FunctionBodyNode* body, ParameterNode* parameter = 0) KJS_FAST_CALL
- : m_ident(ident)
+ FuncExprNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter = 0) JSC_FAST_CALL
+ : ExpressionNode(globalData)
+ , m_ident(ident)
, m_parameter(parameter)
, m_body(body)
{
- addParams();
+ m_body->finishParsing(source, m_parameter.get());
}
- virtual JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+ JSFunction* makeFunction(ExecState*, ScopeChainNode*) JSC_FAST_CALL;
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { return PrecMember; }
virtual bool needsParensIfLeftmost() const { return true; }
- private:
- void addParams() KJS_FAST_CALL;
+ FunctionBodyNode* body() { return m_body.get(); }
+ private:
// Used for streamTo
friend class PropertyNode;
Identifier m_ident;
@@ -2747,54 +2341,50 @@ namespace KJS {
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)
+ FuncDeclNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter = 0) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , m_ident(ident)
, m_parameter(parameter)
, m_body(body)
{
- addParams();
+ m_body->finishParsing(source, m_parameter.get());
}
- virtual JSValue* execute(ExecState*) KJS_FAST_CALL;
- virtual void streamTo(SourceStream&) const KJS_FAST_CALL;
- ALWAYS_INLINE FunctionImp* makeFunction(ExecState*) KJS_FAST_CALL;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ JSFunction* makeFunction(ExecState*, ScopeChainNode*) JSC_FAST_CALL;
Identifier m_ident;
- private:
- void addParams() KJS_FAST_CALL;
+ FunctionBodyNode* body() { return m_body.get(); }
+ private:
RefPtr<ParameterNode> m_parameter;
RefPtr<FunctionBodyNode> m_body;
};
class CaseClauseNode : public Node {
public:
- CaseClauseNode(ExpressionNode* expr) KJS_FAST_CALL
- : m_expr(expr)
+ CaseClauseNode(JSGlobalData* globalData, ExpressionNode* expr) JSC_FAST_CALL
+ : Node(globalData)
+ , m_expr(expr)
{
}
- CaseClauseNode(ExpressionNode* expr, SourceElements* children) KJS_FAST_CALL
- : m_expr(expr)
+ CaseClauseNode(JSGlobalData* globalData, ExpressionNode* expr, SourceElements* children) JSC_FAST_CALL
+ : Node(globalData)
+ , 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 void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
- JSValue* evaluate(ExecState*) KJS_FAST_CALL;
- JSValue* executeStatements(ExecState*) KJS_FAST_CALL;
+ ExpressionNode* expr() const { return m_expr.get(); }
+ StatementVector& children() { return m_children; }
private:
RefPtr<ExpressionNode> m_expr;
@@ -2803,22 +2393,23 @@ namespace KJS {
class ClauseListNode : public Node {
public:
- ClauseListNode(CaseClauseNode* clause) KJS_FAST_CALL
- : m_clause(clause)
+ ClauseListNode(JSGlobalData* globalData, CaseClauseNode* clause) JSC_FAST_CALL
+ : Node(globalData)
+ , m_clause(clause)
{
}
- ClauseListNode(ClauseListNode* clauseList, CaseClauseNode* clause) KJS_FAST_CALL
- : m_clause(clause)
+ ClauseListNode(JSGlobalData* globalData, ClauseListNode* clauseList, CaseClauseNode* clause) JSC_FAST_CALL
+ : Node(globalData)
+ , 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(); }
+ CaseClauseNode* getClause() const JSC_FAST_CALL { return m_clause.get(); }
+ ClauseListNode* getNext() const JSC_FAST_CALL { return m_next.get(); }
+ virtual void streamTo(SourceStream&) const JSC_FAST_CALL;
+ PassRefPtr<ClauseListNode> releaseNext() JSC_FAST_CALL { return m_next.release(); }
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
private:
@@ -2829,14 +2420,21 @@ namespace KJS {
class CaseBlockNode : public Node {
public:
- CaseBlockNode(ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2) KJS_FAST_CALL;
+ CaseBlockNode(JSGlobalData* globalData, ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2) JSC_FAST_CALL
+ : Node(globalData)
+ , m_list1(list1)
+ , m_defaultClause(defaultClause)
+ , m_list2(list2)
+ {
+ }
+
+ RegisterID* emitCodeForBlock(CodeGenerator&, RegisterID* input, RegisterID* dst = 0) JSC_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 void streamTo(SourceStream&) const JSC_FAST_CALL;
virtual Precedence precedence() const { ASSERT_NOT_REACHED(); return PrecExpression; }
private:
+ SwitchInfo::SwitchType tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num);
RefPtr<ClauseListNode> m_list1;
RefPtr<CaseClauseNode> m_defaultClause;
RefPtr<ClauseListNode> m_list2;
@@ -2844,33 +2442,22 @@ namespace KJS {
class SwitchNode : public StatementNode {
public:
- SwitchNode(ExpressionNode* expr, CaseBlockNode* block) KJS_FAST_CALL
- : m_expr(expr)
+ SwitchNode(JSGlobalData* globalData, ExpressionNode* expr, CaseBlockNode* block) JSC_FAST_CALL
+ : StatementNode(globalData)
+ , 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;
+ virtual RegisterID* emitCode(CodeGenerator&, RegisterID* = 0) JSC_FAST_CALL;
+
+ virtual void streamTo(SourceStream&) const JSC_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;
@@ -2901,6 +2488,6 @@ namespace KJS {
ClauseListNode* tail;
};
-} // namespace KJS
+} // namespace JSC
#endif // NODES_H_
diff --git a/JavaScriptCore/kjs/nodes2string.cpp b/JavaScriptCore/kjs/nodes2string.cpp
index b10e180..4afefe0 100644
--- a/JavaScriptCore/kjs/nodes2string.cpp
+++ b/JavaScriptCore/kjs/nodes2string.cpp
@@ -30,7 +30,7 @@
using namespace WTF;
using namespace Unicode;
-namespace KJS {
+namespace JSC {
// A simple text streaming class that helps with code indentation.
@@ -78,7 +78,7 @@ static UString escapeStringForPrettyPrinting(const UString& s)
UString escapedString;
for (int i = 0; i < s.size(); i++) {
- unsigned short c = s.data()[i].unicode();
+ UChar c = s.data()[i];
switch (c) {
case '\"':
escapedString += "\\\"";
@@ -159,7 +159,8 @@ SourceStream& SourceStream::operator<<(char c)
{
m_numberNeedsParens = false;
m_atStartOfStatement = false;
- UChar ch(c);
+ // use unsigned char to zero-extend instead of sign-extend
+ UChar ch(static_cast<unsigned char>(c));
m_string.append(ch);
return *this;
}
@@ -296,18 +297,9 @@ 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 BooleanNode::streamTo(SourceStream& s) const
{
+ s << (m_value ? "true" : "false");
}
void NumberNode::streamTo(SourceStream& s) const
@@ -317,12 +309,12 @@ void NumberNode::streamTo(SourceStream& s) const
void StringNode::streamTo(SourceStream& s) const
{
- s << '"' << escapeStringForPrettyPrinting(m_value) << '"';
+ s << '"' << escapeStringForPrettyPrinting(m_value.ustring()) << '"';
}
void RegExpNode::streamTo(SourceStream& s) const
{
- s << '/' << m_regExp->pattern() << '/' << m_regExp->flags();
+ s << '/' << m_pattern << '/' << m_flags;
}
void ThisNode::streamTo(SourceStream& s) const
@@ -426,6 +418,11 @@ void NewExprNode::streamTo(SourceStream& s) const
s << "new " << PrecMember << m_expr << m_args;
}
+void EvalFunctionCallNode::streamTo(SourceStream& s) const
+{
+ s << "eval" << m_args;
+}
+
void FunctionCallValueNode::streamTo(SourceStream& s) const
{
s << PrecCall << m_expr << m_args;
@@ -448,38 +445,21 @@ void FunctionCallDotNode::streamTo(SourceStream& s) const
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
+void PostfixResolveNode::streamTo(SourceStream& s) const
{
- bracketNodeStreamTo(s, m_base, m_subscript);
- s << "++";
+ s << m_ident << operatorString(m_operator);
}
-void PostDecBracketNode::streamTo(SourceStream& s) const
+void PostfixBracketNode::streamTo(SourceStream& s) const
{
bracketNodeStreamTo(s, m_base, m_subscript);
- s << "--";
-}
-
-void PostIncDotNode::streamTo(SourceStream& s) const
-{
- dotNodeStreamTo(s, m_base, m_ident);
- s << "++";
+ s << operatorString(m_operator);
}
-void PostDecDotNode::streamTo(SourceStream& s) const
+void PostfixDotNode::streamTo(SourceStream& s) const
{
dotNodeStreamTo(s, m_base, m_ident);
- s << "--";
+ s << operatorString(m_operator);
}
void PostfixErrorNode::streamTo(SourceStream& s) const
@@ -528,37 +508,20 @@ void TypeOfResolveNode::streamTo(SourceStream& s) const
s << "typeof " << m_ident;
}
-void PreIncResolveNode::streamTo(SourceStream& s) const
+void PrefixResolveNode::streamTo(SourceStream& s) const
{
- s << "++" << m_ident;
+ s << operatorString(m_operator) << m_ident;
}
-void PreDecResolveNode::streamTo(SourceStream& s) const
+void PrefixBracketNode::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 << "--";
+ s << operatorString(m_operator);
bracketNodeStreamTo(s, m_base, m_subscript);
}
-void PreIncDotNode::streamTo(SourceStream& s) const
+void PrefixDotNode::streamTo(SourceStream& s) const
{
- s << "++";
- dotNodeStreamTo(s, m_base, m_ident);
-}
-
-void PreDecDotNode::streamTo(SourceStream& s) const
-{
- s << "--";
+ s << operatorString(m_operator);
dotNodeStreamTo(s, m_base, m_ident);
}
@@ -592,42 +555,42 @@ void LogicalNotNode::streamTo(SourceStream& s) const
void MultNode::streamTo(SourceStream& s) const
{
- streamLeftAssociativeBinaryOperator(s, precedence(), "*", m_term1, m_term2);
+ streamLeftAssociativeBinaryOperator(s, precedence(), "*", m_expr1, m_expr2);
}
void DivNode::streamTo(SourceStream& s) const
{
- streamLeftAssociativeBinaryOperator(s, precedence(), "/", m_term1, m_term2);
+ streamLeftAssociativeBinaryOperator(s, precedence(), "/", m_expr1, m_expr2);
}
void ModNode::streamTo(SourceStream& s) const
{
- streamLeftAssociativeBinaryOperator(s, precedence(), "%", m_term1, m_term2);
+ streamLeftAssociativeBinaryOperator(s, precedence(), "%", m_expr1, m_expr2);
}
void AddNode::streamTo(SourceStream& s) const
{
- streamLeftAssociativeBinaryOperator(s, precedence(), "+", m_term1, m_term2);
+ streamLeftAssociativeBinaryOperator(s, precedence(), "+", m_expr1, m_expr2);
}
void SubNode::streamTo(SourceStream& s) const
{
- streamLeftAssociativeBinaryOperator(s, precedence(), "-", m_term1, m_term2);
+ streamLeftAssociativeBinaryOperator(s, precedence(), "-", m_expr1, m_expr2);
}
void LeftShiftNode::streamTo(SourceStream& s) const
{
- streamLeftAssociativeBinaryOperator(s, precedence(), "<<", m_term1, m_term2);
+ streamLeftAssociativeBinaryOperator(s, precedence(), "<<", m_expr1, m_expr2);
}
void RightShiftNode::streamTo(SourceStream& s) const
{
- streamLeftAssociativeBinaryOperator(s, precedence(), ">>", m_term1, m_term2);
+ streamLeftAssociativeBinaryOperator(s, precedence(), ">>", m_expr1, m_expr2);
}
void UnsignedRightShiftNode::streamTo(SourceStream& s) const
{
- streamLeftAssociativeBinaryOperator(s, precedence(), ">>>", m_term1, m_term2);
+ streamLeftAssociativeBinaryOperator(s, precedence(), ">>>", m_expr1, m_expr2);
}
void LessNode::streamTo(SourceStream& s) const
@@ -695,14 +658,9 @@ void BitOrNode::streamTo(SourceStream& s) const
streamLeftAssociativeBinaryOperator(s, precedence(), "|", m_expr1, m_expr2);
}
-void LogicalAndNode::streamTo(SourceStream& s) const
+void LogicalOpNode::streamTo(SourceStream& s) const
{
- streamLeftAssociativeBinaryOperator(s, precedence(), "&&", m_expr1, m_expr2);
-}
-
-void LogicalOrNode::streamTo(SourceStream& s) const
-{
- streamLeftAssociativeBinaryOperator(s, precedence(), "||", m_expr1, m_expr2);
+ streamLeftAssociativeBinaryOperator(s, precedence(), (m_operator == OpLogicalAnd) ? "&&" : "||", m_expr1, m_expr2);
}
void ConditionalNode::streamTo(SourceStream& s) const
@@ -761,11 +719,11 @@ void ConstDeclNode::streamTo(SourceStream& s) const
{
s << m_ident;
if (m_init)
- s << " = " << m_init;
+ s << " = " << PrecAssignment << m_init;
for (ConstDeclNode* n = m_next.get(); n; n = n->m_next.get()) {
- s << ", " << m_ident;
- if (m_init)
- s << " = " << m_init;
+ s << ", " << n->m_ident;
+ if (n->m_init)
+ s << " = " << PrecAssignment << n->m_init;
}
}
@@ -814,6 +772,11 @@ void EmptyStatementNode::streamTo(SourceStream& s) const
s << Endl << ';';
}
+void DebuggerStatementNode::streamTo(SourceStream& s) const
+{
+ s << Endl << "debugger;";
+}
+
void ExprStatementNode::streamTo(SourceStream& s) const
{
s << Endl << m_expr << ';';
@@ -936,7 +899,7 @@ void SwitchNode::streamTo(SourceStream& s) const
void LabelNode::streamTo(SourceStream& s) const
{
- s << Endl << m_label << ":" << Indent << m_statement << Unindent;
+ s << Endl << m_name << ":" << Indent << m_statement << Unindent;
}
void ThrowNode::streamTo(SourceStream& s) const
@@ -970,4 +933,4 @@ void FuncExprNode::streamTo(SourceStream& s) const
s << "function " << m_ident << '(' << m_parameter << ')' << m_body;
}
-} // namespace KJS
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/number_object.cpp b/JavaScriptCore/kjs/number_object.cpp
deleted file mode 100644
index 94fc7e7..0000000
--- a/JavaScriptCore/kjs/number_object.cpp
+++ /dev/null
@@ -1,522 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 36befed..0000000
--- a/JavaScriptCore/kjs/number_object.h
+++ /dev/null
@@ -1,76 +0,0 @@
-// -*- 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
deleted file mode 100644
index 7c0653a..0000000
--- a/JavaScriptCore/kjs/object.cpp
+++ /dev/null
@@ -1,693 +0,0 @@
-// -*- 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) {
-#ifdef ANDROID_FIX
- if (imp == imp->_proto)
- break;
-#endif
- 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, int attr)
-{
- 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;
- }
-
- // The put calls from JavaScript execution either have no attributes set, or in some cases
- // have DontDelete set. For those calls, respect the ReadOnly flag.
- bool checkReadOnly = !(attr & ~DontDelete);
-
- // Check if there are any setters or getters in the prototype chain
- JSObject *obj = this;
- bool hasGettersOrSetters = false;
- while (true) {
-#ifdef ANDROID_FIX
- if (obj == obj->_proto)
- break;
-#endif
- if (obj->_prop.hasGetterSetterProperties()) {
- hasGettersOrSetters = true;
- break;
- }
-
- if (!obj->_proto->isObject())
- break;
-
- obj = static_cast<JSObject *>(obj->_proto);
- }
-
- if (hasGettersOrSetters) {
- if (checkReadOnly && !canPut(exec, propertyName))
- return;
-
- obj = this;
- while (true) {
-#ifdef ANDROID_FIX
- if (obj == obj->_proto)
- break;
-#endif
- unsigned attributes;
- 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, attr, checkReadOnly);
-}
-
-void JSObject::put(ExecState *exec, unsigned propertyName,
- JSValue *value, int attr)
-{
- put(exec, Identifier::from(propertyName), value, attr);
-}
-
-// ECMA 8.6.2.3
-bool JSObject::canPut(ExecState *, const Identifier &propertyName) const
-{
- unsigned attributes;
-
- // Don't look in the prototype here. We can always put an override
- // in the object, even if the prototype has a ReadOnly property.
- // Also, there is no need to check the static property table, as this
- // would have been done by the subclass already.
-
- if (!_prop.get(propertyName, attributes))
- return true;
-
- return !(attributes & ReadOnly);
-}
-
-// 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
deleted file mode 100644
index aa32738..0000000
--- a/JavaScriptCore/kjs/object.h
+++ /dev/null
@@ -1,607 +0,0 @@
-// -*- 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
- Internal = 1 << 4, // an internal property, set to bypass checks
- Function = 1 << 5, // property is a function - only used by static hashtables
- GetterSetter = 1 << 6 }; // 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* exec, const Identifier &propertyName, JSValue* value, int attr = None);
- virtual void put(ExecState* exec, unsigned propertyName, JSValue* value, int attr = None);
-
- /**
- * Used to check whether or not a particular property is allowed to be set
- * on an object
- *
- * See ECMA 8.6.2.3
- *
- * @param exec The current execution state
- * @param propertyName The name of the property
- * @return true if the property can be set, otherwise false
- */
- /**
- * Implementation of the [[CanPut]] internal property (implemented by all
- * Objects)
- */
- virtual bool canPut(ExecState *exec, const Identifier &propertyName) const;
-
- /**
- * 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() { 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) {
-#ifdef ANDROID_FIX
- if (object == object->_proto)
- return false;
-#endif
- 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
deleted file mode 100644
index 90eaa93..0000000
--- a/JavaScriptCore/kjs/object_object.cpp
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 0ee5482..0000000
--- a/JavaScriptCore/kjs/object_object.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * 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
index d2b3892..f2d8deb 100644
--- a/JavaScriptCore/kjs/operations.cpp
+++ b/JavaScriptCore/kjs/operations.cpp
@@ -1,7 +1,6 @@
-// -*- c-basic-offset: 2 -*-
/*
- * This file is part of the KDE libraries
- * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
+ * Copyright (C) 2008 Apple Inc. All Rights Reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -23,8 +22,9 @@
#include "config.h"
#include "operations.h"
-#include "internal.h"
-#include "object.h"
+#include "Error.h"
+#include "JSObject.h"
+#include "JSString.h"
#include <math.h>
#include <stdio.h>
#include <wtf/MathExtras.h>
@@ -33,96 +33,43 @@
#include <float.h>
#endif
-namespace KJS {
+namespace JSC {
// ECMA 11.9.3
-bool equal(ExecState *exec, JSValue *v1, JSValue *v2)
+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;
+ if (JSImmediate::areBothImmediateNumbers(v1, v2))
+ return v1 == v2;
+
+ return equalSlowCaseInline(exec, v1, v2);
}
-bool strictEqual(ExecState *exec, JSValue *v1, JSValue *v2)
+bool equalSlowCase(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 equalSlowCaseInline(exec, v1, v2);
+}
+
+bool strictEqual(JSValue* v1, JSValue* v2)
+{
+ if (JSImmediate::areBothImmediate(v1, v2))
+ return v1 == v2;
+
+ if (JSImmediate::isEitherImmediate(v1, v2) & (v1 != JSImmediate::from(0)) & (v2 != JSImmediate::from(0)))
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;
+
+ return strictEqualSlowCaseInline(v1, v2);
+}
+
+bool strictEqualSlowCase(JSValue* v1, JSValue* v2)
+{
+ return strictEqualSlowCaseInline(v1, v2);
}
+NEVER_INLINE JSValue* throwOutOfMemoryError(ExecState* exec)
+{
+ JSObject* error = Error::create(exec, GeneralError, "Out of memory");
+ exec->setException(error);
+ return error;
}
+
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/operations.h b/JavaScriptCore/kjs/operations.h
index 96656f0..fad9720 100644
--- a/JavaScriptCore/kjs/operations.h
+++ b/JavaScriptCore/kjs/operations.h
@@ -1,4 +1,3 @@
-// -*- c-basic-offset: 2 -*-
/*
* This file is part of the KDE libraries
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
@@ -23,13 +22,116 @@
#ifndef _KJS_OPERATIONS_H_
#define _KJS_OPERATIONS_H_
-namespace KJS {
+#include "JSImmediate.h"
+#include "JSNumberCell.h"
+#include "JSString.h"
- class ExecState;
- class JSValue;
+namespace JSC {
- bool equal(ExecState *exec, JSValue *v1, JSValue *v2);
- bool strictEqual(ExecState *exec, JSValue *v1, JSValue *v2);
+ // ECMA 11.9.3
+ bool equal(ExecState*, JSValue*, JSValue*);
+ bool equalSlowCase(ExecState*, JSValue*, JSValue*);
+
+ ALWAYS_INLINE bool equalSlowCaseInline(ExecState* exec, JSValue* v1, JSValue* v2)
+ {
+ ASSERT(!JSImmediate::areBothImmediateNumbers(v1, v2));
+
+ do {
+ if (v1->isNumber() && v2->isNumber())
+ return v1->uncheckedGetNumber() == v2->uncheckedGetNumber();
+
+ bool s1 = v1->isString();
+ bool s2 = v2->isString();
+ if (s1 && s2)
+ return asString(v1)->value() == asString(v2)->value();
+
+ if (v1->isUndefinedOrNull()) {
+ if (v2->isUndefinedOrNull())
+ return true;
+ if (JSImmediate::isImmediate(v2))
+ return false;
+ return v2->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
+ }
+
+ if (v2->isUndefinedOrNull()) {
+ if (JSImmediate::isImmediate(v1))
+ return false;
+ return v1->asCell()->structureID()->typeInfo().masqueradesAsUndefined();
+ }
+
+ if (v1->isObject()) {
+ if (v2->isObject())
+ return v1 == v2;
+ JSValue* p1 = v1->toPrimitive(exec);
+ if (exec->hadException())
+ return false;
+ v1 = p1;
+ if (JSImmediate::areBothImmediateNumbers(v1, v2))
+ return v1 == v2;
+ continue;
+ }
+
+ if (v2->isObject()) {
+ JSValue* p2 = v2->toPrimitive(exec);
+ if (exec->hadException())
+ return false;
+ v2 = p2;
+ if (JSImmediate::areBothImmediateNumbers(v1, v2))
+ return v1 == v2;
+ continue;
+ }
+
+ if (s1 || s2) {
+ double d1 = v1->toNumber(exec);
+ double d2 = v2->toNumber(exec);
+ return d1 == d2;
+ }
+
+ if (v1->isBoolean()) {
+ if (v2->isNumber())
+ return static_cast<double>(v1->getBoolean()) == v2->uncheckedGetNumber();
+ } else if (v2->isBoolean()) {
+ if (v1->isNumber())
+ return v1->uncheckedGetNumber() == static_cast<double>(v2->getBoolean());
+ }
+
+ return v1 == v2;
+ } while (true);
+ }
+
+
+ bool strictEqual(JSValue*, JSValue*);
+ bool strictEqualSlowCase(JSValue*, JSValue*);
+
+ inline bool strictEqualSlowCaseInline(JSValue* v1, JSValue* v2)
+ {
+ ASSERT(!JSImmediate::areBothImmediate(v1, v2));
+
+ if (JSImmediate::isEitherImmediate(v1, v2)) {
+ ASSERT(v1 == JSImmediate::zeroImmediate() || v2 == JSImmediate::zeroImmediate());
+ ASSERT(v1 != v2);
+
+ // The reason we can't just return false here is that 0 === -0,
+ // and while the former is an immediate number, the latter is not.
+ if (v1 == JSImmediate::zeroImmediate())
+ return asCell(v2)->isNumber() && asNumberCell(v2)->value() == 0;
+ return asCell(v1)->isNumber() && asNumberCell(v1)->value() == 0;
+ }
+
+ if (asCell(v1)->isNumber()) {
+ return asCell(v2)->isNumber()
+ && asNumberCell(v1)->value() == asNumberCell(v2)->value();
+ }
+
+ if (asCell(v1)->isString()) {
+ return asCell(v2)->isString()
+ && asString(v1)->value() == asString(v2)->value();
+ }
+
+ return v1 == v2;
+ }
+
+ JSValue* throwOutOfMemoryError(ExecState*);
}
#endif
diff --git a/JavaScriptCore/kjs/property_map.cpp b/JavaScriptCore/kjs/property_map.cpp
deleted file mode 100644
index 1da4917..0000000
--- a/JavaScriptCore/kjs/property_map.cpp
+++ /dev/null
@@ -1,850 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 269e911..0000000
--- a/JavaScriptCore/kjs/property_map.h
+++ /dev/null
@@ -1,184 +0,0 @@
-// -*- 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
deleted file mode 100644
index ef2525f..0000000
--- a/JavaScriptCore/kjs/property_slot.cpp
+++ /dev/null
@@ -1,46 +0,0 @@
-// -*- 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
deleted file mode 100644
index 4ec8b46..0000000
--- a/JavaScriptCore/kjs/property_slot.h
+++ /dev/null
@@ -1,142 +0,0 @@
-// -*- 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
index 912e45c..b317424 100644
--- a/JavaScriptCore/kjs/protect.h
+++ b/JavaScriptCore/kjs/protect.h
@@ -1,7 +1,5 @@
-// -*- c-basic-offset: 2 -*-
/*
- * This file is part of the KDE libraries
- * Copyright (C) 2004 Apple Computer, Inc.
+ * Copyright (C) 2004, 2008 Apple Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
@@ -21,123 +19,136 @@
*/
-#ifndef _KJS_PROTECT_H_
-#define _KJS_PROTECT_H_
+#ifndef protect_h
+#define protect_h
-#include "value.h"
+#include "JSCell.h"
#include "collector.h"
-#include "JSLock.h"
-namespace KJS {
+namespace JSC {
- inline void gcProtect(JSValue *val)
- {
- Collector::protect(val);
+ inline void gcProtect(JSCell* val)
+ {
+ Heap::heap(val)->protect(val);
}
- inline void gcUnprotect(JSValue *val)
- {
- Collector::unprotect(val);
+ inline void gcUnprotect(JSCell* val)
+ {
+ Heap::heap(val)->unprotect(val);
}
- inline void gcProtectNullTolerant(JSValue *val)
+ inline void gcProtectNullTolerant(JSCell* val)
{
if (val)
gcProtect(val);
}
- inline void gcUnprotectNullTolerant(JSValue *val)
+ inline void gcUnprotectNullTolerant(JSCell* val)
{
if (val)
gcUnprotect(val);
}
+ inline void gcProtect(JSValue* value)
+ {
+ if (JSImmediate::isImmediate(value))
+ return;
+ gcProtect(asCell(value));
+ }
+
+ inline void gcUnprotect(JSValue* value)
+ {
+ if (JSImmediate::isImmediate(value))
+ return;
+ gcUnprotect(asCell(value));
+ }
+
+ inline void gcProtectNullTolerant(JSValue* value)
+ {
+ if (!value || JSImmediate::isImmediate(value))
+ return;
+ gcProtect(asCell(value));
+ }
+
+ inline void gcUnprotectNullTolerant(JSValue* value)
+ {
+ if (!value || JSImmediate::isImmediate(value))
+ return;
+ gcUnprotect(asCell(value));
+ }
+
// FIXME: Share more code with RefPtr template? The only differences are the ref/deref operation
// and the implicit conversion to raw pointer
template <class T> class ProtectedPtr {
public:
- ProtectedPtr() : m_ptr(NULL) { }
- ProtectedPtr(T *ptr);
- ProtectedPtr(const ProtectedPtr &);
+ ProtectedPtr() : m_ptr(0) { }
+ ProtectedPtr(T* ptr);
+ ProtectedPtr(const ProtectedPtr&);
~ProtectedPtr();
- template <class U> ProtectedPtr(const ProtectedPtr<U> &);
+ 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; }
+ 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; }
+ bool operator!() const { return !m_ptr; }
- ProtectedPtr &operator=(const ProtectedPtr &);
- ProtectedPtr &operator=(T *);
+ ProtectedPtr& operator=(const ProtectedPtr&);
+ ProtectedPtr& operator=(T*);
private:
- T *m_ptr;
+ T* m_ptr;
};
- template <class T> ProtectedPtr<T>::ProtectedPtr(T *ptr)
+ template <class T> ProtectedPtr<T>::ProtectedPtr(T* ptr)
: m_ptr(ptr)
{
- if (ptr) {
- JSLock lock;
- gcProtect(ptr);
- }
+ gcProtectNullTolerant(m_ptr);
}
- template <class T> ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr &o)
+ template <class T> ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr& o)
: m_ptr(o.get())
{
- if (T *ptr = m_ptr) {
- JSLock lock;
- gcProtect(ptr);
- }
+ gcProtectNullTolerant(m_ptr);
}
template <class T> ProtectedPtr<T>::~ProtectedPtr()
{
- if (T *ptr = m_ptr) {
- JSLock lock;
- gcUnprotect(ptr);
- }
+ gcUnprotectNullTolerant(m_ptr);
}
- template <class T> template <class U> ProtectedPtr<T>::ProtectedPtr(const ProtectedPtr<U> &o)
+ 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);
- }
+ gcProtectNullTolerant(m_ptr);
}
- template <class T> ProtectedPtr<T> &ProtectedPtr<T>::operator=(const ProtectedPtr<T> &o)
+ template <class T> ProtectedPtr<T>& ProtectedPtr<T>::operator=(const ProtectedPtr<T>& o)
{
- JSLock lock;
- T *optr = o.m_ptr;
+ T* optr = o.m_ptr;
gcProtectNullTolerant(optr);
gcUnprotectNullTolerant(m_ptr);
m_ptr = optr;
- return *this;
- }
+ return *this;
+ }
- template <class T> inline ProtectedPtr<T> &ProtectedPtr<T>::operator=(T *optr)
+ 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(); }
- 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
+} // namespace JSC
-#endif
+#endif // protect_h
diff --git a/JavaScriptCore/kjs/regexp.cpp b/JavaScriptCore/kjs/regexp.cpp
index 4839c86..7397232 100644
--- a/JavaScriptCore/kjs/regexp.cpp
+++ b/JavaScriptCore/kjs/regexp.cpp
@@ -1,8 +1,6 @@
-// -*- c-basic-offset: 2 -*-
/*
- * This file is part of the KDE libraries
* Copyright (C) 1999-2001, 2004 Harri Porten (porten@kde.org)
- * Copyright (c) 2007, Apple Inc.
+ * 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
@@ -23,33 +21,52 @@
#include "config.h"
#include "regexp.h"
+#include "CTI.h"
#include "lexer.h"
+#include <pcre/pcre.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <wrec/WREC.h>
#include <wtf/Assertions.h>
+#include <wtf/OwnArrayPtr.h>
-namespace KJS {
+namespace JSC {
-RegExp::RegExp(const UString& pattern)
- : m_pattern(pattern)
- , m_flagBits(0)
- , m_constructionError(0)
- , m_numSubpatterns(0)
+inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern)
+ : m_pattern(pattern)
+ , m_flagBits(0)
+ , m_regExp(0)
+ , m_constructionError(0)
+ , m_numSubpatterns(0)
{
- m_regExp = jsRegExpCompile(reinterpret_cast<const ::UChar*>(pattern.data()), pattern.size(),
+#if ENABLE(WREC)
+ m_wrecFunction = CTI::compileRegExp(globalData->machine, pattern, &m_numSubpatterns, &m_constructionError);
+ if (m_wrecFunction)
+ return;
+ // Fall through to non-WREC case.
+#else
+ UNUSED_PARAM(globalData);
+#endif
+ m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(),
JSRegExpDoNotIgnoreCase, JSRegExpSingleLine, &m_numSubpatterns, &m_constructionError);
}
-RegExp::RegExp(const UString& pattern, const UString& flags)
- : m_pattern(pattern)
- , m_flags(flags)
- , m_flagBits(0)
- , m_constructionError(0)
- , m_numSubpatterns(0)
+PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern)
+{
+ return adoptRef(new RegExp(globalData, pattern));
+}
+
+inline RegExp::RegExp(JSGlobalData* globalData, const UString& pattern, const UString& flags)
+ : m_pattern(pattern)
+ , m_flags(flags)
+ , m_flagBits(0)
+ , m_regExp(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.
+ // String::match and RegExpObject::match.
if (flags.find('g') != -1)
m_flagBits |= Global;
@@ -65,56 +82,101 @@ RegExp::RegExp(const UString& pattern, const UString& flags)
m_flagBits |= Multiline;
multilineOption = JSRegExpMultiline;
}
-
- m_regExp = jsRegExpCompile(reinterpret_cast<const ::UChar*>(pattern.data()), pattern.size(),
+
+#if ENABLE(WREC)
+ m_wrecFunction = CTI::compileRegExp(globalData->machine, pattern, &m_numSubpatterns, &m_constructionError, (m_flagBits & IgnoreCase), (m_flagBits & Multiline));
+ if (m_wrecFunction)
+ return;
+ // Fall through to non-WREC case.
+#else
+ UNUSED_PARAM(globalData);
+#endif
+ m_regExp = jsRegExpCompile(reinterpret_cast<const UChar*>(pattern.data()), pattern.size(),
ignoreCaseOption, multilineOption, &m_numSubpatterns, &m_constructionError);
}
+PassRefPtr<RegExp> RegExp::create(JSGlobalData* globalData, const UString& pattern, const UString& flags)
+{
+ return adoptRef(new RegExp(globalData, pattern, flags));
+}
+
RegExp::~RegExp()
{
jsRegExpFree(m_regExp);
+#if ENABLE(WREC)
+ if (m_wrecFunction)
+ WTF::fastFreeExecutable(m_wrecFunction);
+#endif
}
int RegExp::match(const UString& s, int i, OwnArrayPtr<int>* ovector)
{
- if (i < 0)
- i = 0;
- if (ovector)
- ovector->clear();
+ if (i < 0)
+ i = 0;
+ if (ovector)
+ ovector->clear();
- if (i > s.size() || s.isNull())
- return -1;
+ if (i > s.size() || s.isNull())
+ return -1;
- if (!m_regExp)
- return -1;
+#if ENABLE(WREC)
+ if (m_wrecFunction) {
+ int offsetVectorSize = (m_numSubpatterns + 1) * 2;
+ int* offsetVector = new int [offsetVectorSize];
+ for (int j = 0; j < offsetVectorSize; ++j)
+ offsetVector[j] = -1;
+
+ OwnArrayPtr<int> nonReturnedOvector;
+ if (!ovector)
+ nonReturnedOvector.set(offsetVector);
+ else
+ ovector->set(offsetVector);
+
+ int result = reinterpret_cast<WRECFunction>(m_wrecFunction)(s.data(), i, s.size(), offsetVector);
- // 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) {
+ if (result < 0) {
#ifndef NDEBUG
- if (numMatches != JSRegExpErrorNoMatch)
- fprintf(stderr, "jsRegExpExecute failed with result %d\n", numMatches);
+ // TODO: define up a symbol, rather than magic -1
+ if (result != -1)
+ fprintf(stderr, "jsRegExpExecute failed with result %d\n", result);
#endif
- if (ovector)
- ovector->clear();
- return -1;
- }
+ if (ovector)
+ ovector->clear();
+ }
+ return result;
+ } else
+#endif
+ if (m_regExp) {
+ // Set up the offset vector for the result.
+ // First 2/3 used for result, the last third used by PCRE.
+ int* offsetVector;
+ int offsetVectorSize;
+ int fixedSizeOffsetVector[3];
+ if (!ovector) {
+ offsetVectorSize = 3;
+ offsetVector = fixedSizeOffsetVector;
+ } else {
+ offsetVectorSize = (m_numSubpatterns + 1) * 3;
+ 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];
+ return offsetVector[0];
+ }
+
+ return -1;
}
-} // namespace KJS
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/regexp.h b/JavaScriptCore/kjs/regexp.h
index 2c62085..1842d94 100644
--- a/JavaScriptCore/kjs/regexp.h
+++ b/JavaScriptCore/kjs/regexp.h
@@ -1,7 +1,6 @@
-// -*- c-basic-offset: 2 -*-
/*
* Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2007 Apple Inc. All rights reserved.
+ * 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
@@ -23,53 +22,55 @@
#define KJS_REGEXP_H
#include "ustring.h"
-#include <pcre/pcre.h>
-#include <sys/types.h>
-#include <wtf/OwnArrayPtr.h>
+#include <wtf/Forward.h>
#include <wtf/RefCounted.h>
-namespace KJS {
+struct JSRegExp;
- class RegExp : public RefCounted<RegExp> {
- private:
- enum {
- Global = 1,
- IgnoreCase = 2,
- Multiline = 4
- };
+namespace JSC {
+
+ class JSGlobalData;
+
+ class RegExp : public RefCounted<RegExp> {
+ public:
+ static PassRefPtr<RegExp> create(JSGlobalData*, const UString& pattern);
+ static PassRefPtr<RegExp> create(JSGlobalData*, 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; }
- public:
- RegExp(const UString& pattern);
- RegExp(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; }
- 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; }
- 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; }
- int match(const UString&, int offset, OwnArrayPtr<int>* ovector = 0);
- unsigned numSubpatterns() const { return m_numSubpatterns; }
+ private:
+ RegExp(JSGlobalData*, const UString& pattern);
+ RegExp(JSGlobalData*, const UString& pattern, const UString& flags);
- private:
- void compile();
-
- // Data supplied by caller.
- 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;
+ void compile();
- // Data supplied by PCRE.
- JSRegExp* m_regExp;
- const char* m_constructionError;
- unsigned m_numSubpatterns;
- };
+ enum FlagBits { Global = 1, IgnoreCase = 2, Multiline = 4 };
-} // namespace
+ 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;
+#if ENABLE(WREC)
+ // Called as a WRECFunction
+ void* m_wrecFunction;
#endif
+ };
+
+} // namespace JSC
+
+#endif // KJS_REGEXP_H
diff --git a/JavaScriptCore/kjs/regexp_object.cpp b/JavaScriptCore/kjs/regexp_object.cpp
deleted file mode 100644
index 217c8db..0000000
--- a/JavaScriptCore/kjs/regexp_object.cpp
+++ /dev/null
@@ -1,475 +0,0 @@
-/*
- * 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 = new RegExp(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, int attributes)
-{
- lookupPut<RegExpImp, JSObject>(exec, propertyName, value, attributes, &RegExpImpTable, this);
-}
-
-void RegExpImp::putValueProperty(ExecState* exec, int token, JSValue* value, int)
-{
- 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, int attr)
-{
- lookupPut<RegExpObjectImp, InternalFunctionImp>(exec, propertyName, value, attr, &RegExpObjectImpTable, this);
-}
-
-void RegExpObjectImp::putValueProperty(ExecState *exec, int token, JSValue *value, int)
-{
- 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, new RegExp(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
deleted file mode 100644
index 1ce2f16..0000000
--- a/JavaScriptCore/kjs/regexp_object.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * 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*, int attributes = None);
- void putValueProperty(ExecState*, int token, JSValue*, int attributes);
-
- 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*, int attributes = None);
- void putValueProperty(ExecState*, int token, JSValue*, int attributes);
- 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
deleted file mode 100644
index aba066a..0000000
--- a/JavaScriptCore/kjs/scope_chain.cpp
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 7441cb8..0000000
--- a/JavaScriptCore/kjs/scope_chain.h
+++ /dev/null
@@ -1,156 +0,0 @@
-/*
- * 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
deleted file mode 100644
index bc4d5f8..0000000
--- a/JavaScriptCore/kjs/scope_chain_mark.h
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 53b6ada..0000000
--- a/JavaScriptCore/kjs/string_object.cpp
+++ /dev/null
@@ -1,1055 +0,0 @@
-// -*- 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, int attr)
-{
- if (propertyName == exec->propertyNames().length)
- return;
- JSObject::put(exec, propertyName, value, attr);
-}
-
-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;
- RegExp* reg;
- RegExp* tmpReg = 0;
- 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 = tmpReg = new RegExp(a0->toString(exec));
- }
- RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalGlobalObject()->regExpConstructor());
- int pos;
- int matchLength;
- regExpObj->performMatch(reg, 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, 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);
- }
- }
- delete tmpReg;
- 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;
- RegExp* reg;
- RegExp* tmpReg = 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 = tmpReg = new RegExp(a0->toString(exec));
- }
- RegExpObjectImp* regExpObj = static_cast<RegExpObjectImp*>(exec->lexicalGlobalObject()->regExpConstructor());
- int pos;
- int matchLength;
- regExpObj->performMatch(reg, u, 0, pos, matchLength);
- delete tmpReg;
- 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
deleted file mode 100644
index 3bc9cb2..0000000
--- a/JavaScriptCore/kjs/string_object.h
+++ /dev/null
@@ -1,153 +0,0 @@
-// -*- 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*, int attr = None);
- 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
deleted file mode 100644
index 25c807e..0000000
--- a/JavaScriptCore/kjs/testkjs.cpp
+++ /dev/null
@@ -1,344 +0,0 @@
-// -*- c-basic-offset: 2 -*-
-/*
- * Copyright (C) 1999-2000 Harri Porten (porten@kde.org)
- * Copyright (C) 2004-2007 Apple Inc.
- * 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 "collector.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);
-
-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 GlobalImp : public JSGlobalObject {
-public:
- virtual UString className() const { return "global"; }
-};
-COMPILE_ASSERT(!IsInteger<GlobalImp>::value, WTF_IsInteger_GlobalImp_false);
-
-class TestFunctionImp : public JSObject {
-public:
- enum TestFunctionType { Print, Debug, Quit, GC, Version, Run, Load };
-
- TestFunctionImp(TestFunctionType i, int length);
- virtual bool implementsCall() const { return true; }
- virtual JSValue* callAsFunction(ExecState* exec, JSObject* thisObj, const List &args);
-
-private:
- TestFunctionType m_type;
-};
-
-TestFunctionImp::TestFunctionImp(TestFunctionType i, int length)
- : JSObject()
- , m_type(i)
-{
- putDirect(Identifier("length"), length, DontDelete | ReadOnly | DontEnum);
-}
-
-JSValue* TestFunctionImp::callAsFunction(ExecState* exec, JSObject*, const List &args)
-{
- switch (m_type) {
- case Print:
- printf("%s\n", args[0]->toString(exec).UTF8String().c_str());
- return jsUndefined();
- case Debug:
- fprintf(stderr, "--> %s\n", args[0]->toString(exec).UTF8String().c_str());
- return jsUndefined();
- case GC:
- {
- JSLock lock;
- Collector::collect();
- return jsUndefined();
- }
- case Version:
- // 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();
- case Run:
- {
- 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());
- }
- case Load:
- {
- 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();
- }
- case Quit:
- exit(0);
- default:
- abort();
- }
- return 0;
-}
-
-// 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 GlobalImp* createGlobalObject()
-{
- GlobalImp* global = new GlobalImp;
-
- // add debug() function
- global->put(global->globalExec(), "debug", new TestFunctionImp(TestFunctionImp::Debug, 1));
- // add "print" for compatibility with the mozilla js shell
- global->put(global->globalExec(), "print", new TestFunctionImp(TestFunctionImp::Print, 1));
- // add "quit" for compatibility with the mozilla js shell
- global->put(global->globalExec(), "quit", new TestFunctionImp(TestFunctionImp::Quit, 0));
- // add "gc" for compatibility with the mozilla js shell
- global->put(global->globalExec(), "gc", new TestFunctionImp(TestFunctionImp::GC, 0));
- // add "version" for compatibility with the mozilla js shell
- global->put(global->globalExec(), "version", new TestFunctionImp(TestFunctionImp::Version, 1));
- global->put(global->globalExec(), "run", new TestFunctionImp(TestFunctionImp::Run, 1));
- global->put(global->globalExec(), "load", new TestFunctionImp(TestFunctionImp::Load, 1));
-
- Interpreter::setShouldPrintExceptions(true);
- return global;
-}
-
-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, bool prettyPrint)
-{
- GlobalImp* globalObject = createGlobalObject();
- 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 parseArguments(int argc, char** argv, Vector<UString>& fileNames, bool& prettyPrint)
-{
- if (argc < 2) {
- fprintf(stderr, "Usage: testkjs file1 [file2...]\n");
- exit(-1);
- }
-
- for (int i = 1; i < argc; i++) {
- const char* fileName = argv[i];
- if (strcmp(fileName, "-f") == 0) // mozilla test driver script uses "-f" prefix for files
- continue;
- if (strcmp(fileName, "-p") == 0) {
- prettyPrint = true;
- continue;
- }
- fileNames.append(fileName);
- }
-}
-
-int kjsmain(int argc, char** argv)
-{
- JSLock lock;
-
- bool prettyPrint = false;
- Vector<UString> fileNames;
- parseArguments(argc, argv, fileNames, prettyPrint);
-
- bool success = runWithScripts(fileNames, 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
deleted file mode 100644
index ab3016b..0000000
--- a/JavaScriptCore/kjs/testkjs.pro
+++ /dev/null
@@ -1,34 +0,0 @@
-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
-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
deleted file mode 100644
index 603b2a2..0000000
--- a/JavaScriptCore/kjs/types.h
+++ /dev/null
@@ -1,25 +0,0 @@
-// -*- 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
index b658a8d..3a85b1d 100644
--- a/JavaScriptCore/kjs/ustring.cpp
+++ b/JavaScriptCore/kjs/ustring.cpp
@@ -1,7 +1,6 @@
-// -*- 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) 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved.
* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca)
*
* This library is free software; you can redistribute it and/or
@@ -24,10 +23,9 @@
#include "config.h"
#include "ustring.h"
-#include "JSLock.h"
+#include "JSGlobalObjectFunctions.h"
#include "collector.h"
#include "dtoa.h"
-#include "function.h"
#include "identifier.h"
#include "operations.h"
#include <ctype.h>
@@ -36,8 +34,8 @@
#include <math.h>
#include <stdio.h>
#include <stdlib.h>
-#include <wtf/Assertions.h>
#include <wtf/ASCIICType.h>
+#include <wtf/Assertions.h>
#include <wtf/MathExtras.h>
#include <wtf/Vector.h>
#include <wtf/unicode/UTF8.h>
@@ -53,20 +51,25 @@ using namespace WTF;
using namespace WTF::Unicode;
using namespace std;
-namespace KJS {
+// This can be tuned differently per platform by putting platform #ifs right here.
+// If you don't define this macro at all, then copyChars will just call directly
+// to memcpy.
+#define USTRING_COPY_CHARS_INLINE_CUTOFF 20
+namespace JSC {
+
extern const double NaN;
extern const double Inf;
-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 size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); }
+static inline size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); }
static inline UChar* allocChars(size_t length)
{
ASSERT(length);
if (length > maxUChars())
return 0;
- return static_cast<UChar*>(fastMalloc(sizeof(UChar) * length));
+ return static_cast<UChar*>(tryFastMalloc(sizeof(UChar) * length));
}
static inline UChar* reallocChars(UChar* buffer, size_t length)
@@ -74,177 +77,211 @@ 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));
+ return static_cast<UChar*>(tryFastRealloc(buffer, sizeof(UChar) * length));
+}
+
+static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters)
+{
+#ifdef USTRING_COPY_CHARS_INLINE_CUTOFF
+ if (numCharacters <= USTRING_COPY_CHARS_INLINE_CUTOFF) {
+ for (unsigned i = 0; i < numCharacters; ++i)
+ destination[i] = source[i];
+ return;
+ }
+#endif
+ memcpy(destination, source, numCharacters * sizeof(UChar));
}
COMPILE_ASSERT(sizeof(UChar) == 2, uchar_is_2_bytes)
-CString::CString(const char *c)
+CString::CString(const char* c)
+ : m_length(strlen(c))
+ , m_data(new char[m_length + 1])
{
- length = strlen(c);
- data = new char[length+1];
- memcpy(data, c, length + 1);
+ memcpy(m_data, c, m_length + 1);
}
-CString::CString(const char *c, size_t len)
+CString::CString(const char* c, size_t length)
+ : m_length(length)
+ , m_data(new char[length + 1])
{
- length = len;
- data = new char[len+1];
- memcpy(data, c, len);
- data[len] = 0;
+ memcpy(m_data, c, m_length);
+ m_data[m_length] = 0;
}
-CString::CString(const CString &b)
+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;
+ m_length = b.m_length;
+ if (b.m_data) {
+ m_data = new char[m_length + 1];
+ memcpy(m_data, b.m_data, m_length + 1);
+ } else
+ m_data = 0;
}
CString::~CString()
{
- delete [] data;
+ delete [] m_data;
}
-CString &CString::append(const CString &t)
+CString CString::adopt(char* c, size_t length)
{
- 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;
+ CString s;
+ s.m_data = c;
+ s.m_length = length;
+ return s;
+}
- delete [] data;
- data = n;
+CString& CString::append(const CString& t)
+{
+ char* n;
+ n = new char[m_length + t.m_length + 1];
+ if (m_length)
+ memcpy(n, m_data, m_length);
+ if (t.m_length)
+ memcpy(n + m_length, t.m_data, t.m_length);
+ m_length += t.m_length;
+ n[m_length] = 0;
+
+ delete [] m_data;
+ m_data = n;
- return *this;
+ return *this;
}
-CString &CString::operator=(const char *c)
+CString& CString::operator=(const char* c)
{
- if (data)
- delete [] data;
- length = strlen(c);
- data = new char[length+1];
- memcpy(data, c, length + 1);
+ if (m_data)
+ delete [] m_data;
+ m_length = strlen(c);
+ m_data = new char[m_length + 1];
+ memcpy(m_data, c, m_length + 1);
- return *this;
+ return *this;
}
-CString &CString::operator=(const CString &str)
+CString& CString::operator=(const CString& str)
{
- if (this == &str)
- return *this;
+ 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;
+ if (m_data)
+ delete [] m_data;
+ m_length = str.m_length;
+ if (str.m_data) {
+ m_data = new char[m_length + 1];
+ memcpy(m_data, str.m_data, m_length + 1);
+ } else
+ m_data = 0;
- return *this;
+ 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);
+ 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);
+// These static strings are immutable, except for rc, whose initial value is chosen to
+// reduce the possibility of it becoming zero due to ref/deref not being thread-safe.
+static UChar sharedEmptyChar;
+UString::Rep UString::Rep::null = { 0, 0, INT_MAX / 2, 0, 1, &UString::Rep::null, 0, 0, 0, 0, 0, 0 };
+UString::Rep UString::Rep::empty = { 0, 0, INT_MAX / 2, 0, 1, &UString::Rep::empty, 0, &sharedEmptyChar, 0, 0, 0, 0 };
- int sizeInBytes = l * sizeof(UChar);
- UChar *copyD = static_cast<UChar *>(fastMalloc(sizeInBytes));
- memcpy(copyD, d, sizeInBytes);
+static char* statBuffer = 0; // Only used for debugging via UString::ascii().
- return create(copyD, l);
+PassRefPtr<UString::Rep> UString::Rep::createCopying(const UChar* d, int l)
+{
+ UChar* copyD = static_cast<UChar*>(fastMalloc(l * sizeof(UChar)));
+ copyChars(copyD, d, l);
+ return create(copyD, l);
}
-PassRefPtr<UString::Rep> UString::Rep::create(UChar *d, int 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);
+ Rep* r = new Rep;
+ r->offset = 0;
+ r->len = l;
+ r->rc = 1;
+ r->_hash = 0;
+ r->m_identifierTable = 0;
+ r->baseString = r;
+ r->reportedCost = 0;
+ r->buf = d;
+ r->usedCapacity = l;
+ r->capacity = l;
+ r->usedPreCapacity = 0;
+ r->preCapacity = 0;
+
+ r->checkConsistency();
+
+ // 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(base);
+ base->checkConsistency();
+
+ 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->m_identifierTable = 0;
+ r->baseString = base.releaseRef();
+ r->reportedCost = 0;
+ r->buf = 0;
+ r->usedCapacity = 0;
+ r->capacity = 0;
+ r->usedPreCapacity = 0;
+ r->preCapacity = 0;
+
+ r->checkConsistency();
+
+ // steal the single reference this Rep was created with
+ return adoptRef(r);
+}
- ASSERT(-(offset + baseOffset) <= base->usedPreCapacity);
- ASSERT(offset + baseOffset + length <= base->usedCapacity);
+PassRefPtr<UString::Rep> UString::Rep::createFromUTF8(const char* string)
+{
+ if (!string)
+ return &UString::Rep::null;
- 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;
+ size_t length = strlen(string);
+ Vector<UChar, 1024> buffer(length);
+ UChar* p = buffer.data();
+ if (conversionOK != convertUTF8ToUTF16(&string, string + length, &p, p + length))
+ return &UString::Rep::null;
- // steal the single reference this Rep was created with
- return adoptRef(r);
+ return UString::Rep::createCopying(buffer.data(), p - buffer.data());
}
void UString::Rep::destroy()
{
- ASSERT(JSLock::lockCount() > 0);
-
- if (isIdentifier)
- Identifier::remove(this);
- if (baseString != this) {
- baseString->deref();
- } else {
- fastFree(buf);
- }
- delete this;
+ checkConsistency();
+
+ // Static null and empty strings can never be destroyed, but we cannot rely on
+ // reference counting, because ref/deref are not thread-safe.
+ if (!isStatic()) {
+ if (identifierTable())
+ Identifier::remove(this);
+ if (baseString == this)
+ fastFree(buf);
+ else
+ baseString->deref();
+
+ delete this;
+ }
}
// Golden ratio - arbitrary start value to avoid mapping all 0's to all 0's
@@ -253,96 +290,126 @@ 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;
+unsigned UString::Rep::computeHash(const UChar* s, int len)
+{
+ unsigned l = len;
+ uint32_t hash = PHI;
+ uint32_t tmp;
+
+ int rem = l & 1;
+ l >>= 1;
+
+ // Main loop
+ for (; l > 0; l--) {
+ hash += s[0];
+ tmp = (s[1] << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ s += 2;
+ hash += hash >> 11;
+ }
+
+ // Handle end case
+ if (rem) {
+ hash += s[0];
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ }
+
+ // Force "avalanching" of final 127 bits
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 2;
+ hash += hash >> 15;
+ hash ^= hash << 10;
+
+ // this avoids ever returning a hash code of 0, since that is used to
+ // signal "hash not computed yet", using a value that is likely to be
+ // effectively the same as 0 when the low bits are masked
+ if (hash == 0)
+ hash = 0x80000000;
+
+ return hash;
}
// Paul Hsieh's SuperFastHash
// http://www.azillionmonkeys.com/qed/hash.html
-unsigned UString::Rep::computeHash(const char *s)
+unsigned UString::Rep::computeHash(const char* s, int l)
{
- // This hash is designed to work on 16-bit chunks at a time. But since the normal case
- // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
- // were 16-bit chunks, which should give matching results
+ // This hash is designed to work on 16-bit chunks at a time. But since the normal case
+ // (above) is to hash UTF-16 characters, we just treat the 8-bit chars as if they
+ // were 16-bit chunks, which should give matching results
+
+ uint32_t hash = PHI;
+ uint32_t tmp;
+
+ size_t rem = l & 1;
+ l >>= 1;
+
+ // Main loop
+ for (; l > 0; l--) {
+ hash += static_cast<unsigned char>(s[0]);
+ tmp = (static_cast<unsigned char>(s[1]) << 11) ^ hash;
+ hash = (hash << 16) ^ tmp;
+ s += 2;
+ hash += hash >> 11;
+ }
- 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;
+ // Handle end case
+ if (rem) {
+ hash += static_cast<unsigned char>(s[0]);
+ hash ^= hash << 11;
+ hash += hash >> 17;
+ }
+
+ // Force "avalanching" of final 127 bits
+ hash ^= hash << 3;
+ hash += hash >> 5;
+ hash ^= hash << 2;
+ hash += hash >> 15;
+ hash ^= hash << 10;
- return hash;
+ // this avoids ever returning a hash code of 0, since that is used to
+ // signal "hash not computed yet", using a value that is likely to be
+ // effectively the same as 0 when the low bits are masked
+ if (hash == 0)
+ hash = 0x80000000;
+
+ return hash;
}
+#ifndef NDEBUG
+void UString::Rep::checkConsistency() const
+{
+ // Only base strings have non-zero shared data.
+ if (this != baseString) {
+ ASSERT(!buf);
+ ASSERT(!usedCapacity);
+ ASSERT(!capacity);
+ ASSERT(!usedPreCapacity);
+ ASSERT(!preCapacity);
+ }
+
+ // There is no recursion for base strings.
+ ASSERT(baseString == baseString->baseString);
+
+ if (isStatic()) {
+ // There are only two static strings: null and empty.
+ ASSERT(!len);
+
+ // Static strings cannot get in identifier tables, because they are globally shared.
+ ASSERT(!identifierTable());
+ }
+
+ // The string fits in buffer.
+ ASSERT(baseString->usedPreCapacity <= baseString->preCapacity);
+ ASSERT(baseString->usedCapacity <= baseString->capacity);
+ ASSERT(-offset <= baseString->usedPreCapacity);
+ ASSERT(offset + len <= baseString->usedCapacity);
+}
+#endif
+
// put these early so they can be inlined
-inline size_t UString::expandedSize(size_t size, size_t otherSize) const
+static inline size_t expandedSize(size_t size, size_t otherSize)
{
// Do the size calculation in two parts, returning overflowIndicator if
// we overflow the maximum value that we can handle.
@@ -359,97 +426,112 @@ inline size_t UString::expandedSize(size_t size, size_t otherSize) const
inline int UString::usedCapacity() const
{
- return m_rep->baseString->usedCapacity;
+ return m_rep->baseString->usedCapacity;
}
inline int UString::usedPreCapacity() const
{
- return m_rep->baseString->usedPreCapacity;
+ 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;
+static inline bool expandCapacity(UString::Rep* rep, int requiredLength)
+{
+ rep->checkConsistency();
+
+ UString::Rep* r = 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;
+ return false;
+ }
+ r->capacity = newCapacity - r->preCapacity;
}
- r->capacity = newCapacity - r->preCapacity;
- }
- if (requiredLength > r->usedCapacity) {
- r->usedCapacity = requiredLength;
- }
+ if (requiredLength > r->usedCapacity)
+ r->usedCapacity = requiredLength;
+
+ rep->checkConsistency();
+ return true;
+}
+
+void UString::expandCapacity(int requiredLength)
+{
+ if (!JSC::expandCapacity(m_rep.get(), requiredLength))
+ makeNull();
}
void UString::expandPreCapacity(int requiredPreCap)
{
- Rep* r = m_rep->baseString;
+ m_rep->checkConsistency();
- if (requiredPreCap > r->preCapacity) {
- size_t newCapacity = expandedSize(requiredPreCap, r->capacity);
- int delta = newCapacity - r->capacity - r->preCapacity;
+ Rep* r = m_rep->baseString;
- UChar* newBuf = allocChars(newCapacity);
- if (!newBuf) {
- m_rep = &Rep::null;
- return;
+ if (requiredPreCap > r->preCapacity) {
+ size_t newCapacity = expandedSize(requiredPreCap, r->capacity);
+ int delta = newCapacity - r->capacity - r->preCapacity;
+
+ UChar* newBuf = allocChars(newCapacity);
+ if (!newBuf) {
+ makeNull();
+ return;
+ }
+ copyChars(newBuf + delta, r->buf, r->capacity + r->preCapacity);
+ fastFree(r->buf);
+ r->buf = newBuf;
+
+ r->preCapacity = newCapacity - r->capacity;
}
- memcpy(newBuf + delta, r->buf, (r->capacity + r->preCapacity) * sizeof(UChar));
- fastFree(r->buf);
- r->buf = newBuf;
+ if (requiredPreCap > r->usedPreCapacity)
+ r->usedPreCapacity = requiredPreCap;
- r->preCapacity = newCapacity - r->capacity;
- }
- if (requiredPreCap > r->usedPreCapacity) {
- r->usedPreCapacity = requiredPreCap;
- }
+ m_rep->checkConsistency();
}
-UString::UString(const char *c)
+PassRefPtr<UString::Rep> createRep(const char* c)
{
- if (!c) {
- m_rep = &Rep::null;
- return;
- }
+ if (!c)
+ return &UString::Rep::null;
- if (!c[0]) {
- m_rep = &Rep::empty;
- return;
- }
+ if (!c[0])
+ return &UString::Rep::empty;
+
+ size_t length = strlen(c);
+ UChar* d = allocChars(length);
+ if (!d)
+ return &UString::Rep::null;
+ else {
+ for (size_t i = 0; i < length; i++)
+ d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
+ return UString::Rep::create(d, static_cast<int>(length));
+ }
- 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)
+UString::UString(const char* c)
+ : m_rep(createRep(c))
{
- if (length == 0)
- m_rep = &Rep::empty;
- else
- m_rep = Rep::createCopying(c, length);
}
-UString::UString(UChar *c, int length, bool copy)
+UString::UString(const UChar* c, int length)
{
- if (length == 0)
- m_rep = &Rep::empty;
- else if (copy)
- m_rep = Rep::createCopying(c, length);
- else
- m_rep = Rep::create(c, 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)
@@ -460,435 +542,647 @@ UString::UString(const Vector<UChar>& buffer)
m_rep = Rep::createCopying(buffer.data(), buffer.size());
}
+static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const UChar* tData, int tSize)
+{
+ RefPtr<UString::Rep> rep = r;
+
+ rep->checkConsistency();
+
+ int thisSize = rep->size();
+ int thisOffset = rep->offset;
+ int length = thisSize + tSize;
+
+ // possible cases:
+ if (tSize == 0) {
+ // t is empty
+ } else if (thisSize == 0) {
+ // this is empty
+ rep = UString::Rep::createCopying(tData, tSize);
+ } else if (rep->baseIsSelf() && rep->rc == 1) {
+ // this is direct and has refcount of 1 (so we can just alter it directly)
+ if (!expandCapacity(rep.get(), thisOffset + length))
+ rep = &UString::Rep::null;
+ if (rep->data()) {
+ copyChars(rep->data() + thisSize, tData, tSize);
+ rep->len = length;
+ rep->_hash = 0;
+ }
+ } else if (thisOffset + thisSize == rep->baseString->usedCapacity && thisSize >= minShareSize) {
+ // this reaches the end of the buffer - extend it if it's long enough to append to
+ if (!expandCapacity(rep.get(), thisOffset + length))
+ rep = &UString::Rep::null;
+ if (rep->data()) {
+ copyChars(rep->data() + thisSize, tData, tSize);
+ rep = UString::Rep::create(rep, 0, length);
+ }
+ } else {
+ // this is shared with someone using more capacity, gotta make a whole new string
+ size_t newCapacity = expandedSize(length, 0);
+ UChar* d = allocChars(newCapacity);
+ if (!d)
+ rep = &UString::Rep::null;
+ else {
+ copyChars(d, rep->data(), thisSize);
+ copyChars(d + thisSize, tData, tSize);
+ rep = UString::Rep::create(d, length);
+ rep->capacity = newCapacity;
+ }
+ }
+
+ rep->checkConsistency();
+
+ return rep.release();
+}
+
+static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Rep> r, const char* t)
+{
+ RefPtr<UString::Rep> rep = r;
+
+ rep->checkConsistency();
+
+ int thisSize = rep->size();
+ int thisOffset = rep->offset;
+ int tSize = static_cast<int>(strlen(t));
+ int length = thisSize + tSize;
+
+ // possible cases:
+ if (thisSize == 0) {
+ // this is empty
+ rep = createRep(t);
+ } else if (tSize == 0) {
+ // t is empty, we'll just return *this below.
+ } else if (rep->baseIsSelf() && rep->rc == 1) {
+ // this is direct and has refcount of 1 (so we can just alter it directly)
+ expandCapacity(rep.get(), thisOffset + length);
+ UChar* d = rep->data();
+ if (d) {
+ for (int i = 0; i < tSize; ++i)
+ d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
+ rep->len = length;
+ rep->_hash = 0;
+ }
+ } else if (thisOffset + thisSize == rep->baseString->usedCapacity && thisSize >= minShareSize) {
+ // this string reaches the end of the buffer - extend it
+ expandCapacity(rep.get(), thisOffset + length);
+ UChar* d = rep->data();
+ if (d) {
+ for (int i = 0; i < tSize; ++i)
+ d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
+ rep = UString::Rep::create(rep, 0, length);
+ }
+ } else {
+ // this is shared with someone using more capacity, gotta make a whole new string
+ size_t newCapacity = expandedSize(length, 0);
+ UChar* d = allocChars(newCapacity);
+ if (!d)
+ rep = &UString::Rep::null;
+ else {
+ copyChars(d, rep->data(), thisSize);
+ for (int i = 0; i < tSize; ++i)
+ d[thisSize + i] = static_cast<unsigned char>(t[i]); // use unsigned char to zero-extend instead of sign-extend
+ rep = UString::Rep::create(d, length);
+ rep->capacity = newCapacity;
+ }
+ }
+
+ rep->checkConsistency();
-UString::UString(const UString &a, const UString &b)
+ return rep.release();
+}
+
+PassRefPtr<UString::Rep> concatenate(UString::Rep* a, UString::Rep* 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;
+ a->checkConsistency();
+ b->checkConsistency();
+
+ int aSize = a->size();
+ int aOffset = a->offset;
+ int bSize = b->size();
+ int bOffset = b->offset;
+ int length = aSize + bSize;
+
+ // possible cases:
- // possible cases:
-
- if (aSize == 0) {
// a is empty
- m_rep = b.m_rep;
- } else if (bSize == 0) {
+ if (aSize == 0)
+ return b;
// 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 {
+ if (bSize == 0)
+ return a;
+
+ if (bSize == 1 && aOffset + aSize == a->baseString->usedCapacity && aOffset + length <= a->baseString->capacity) {
+ // b is a single character (common fast case)
+ a->baseString->usedCapacity = aOffset + length;
+ a->data()[aSize] = b->data()[0];
+ return UString::Rep::create(a, 0, length);
+ }
+
+ if (aOffset + aSize == a->baseString->usedCapacity && aSize >= minShareSize && 4 * aSize >= bSize &&
+ (-bOffset != b->baseString->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())
+ return 0;
+ copyChars(a->data() + aSize, b->data(), bSize);
+ PassRefPtr<UString::Rep> result = UString::Rep::create(a, 0, length);
+
+ a->checkConsistency();
+ b->checkConsistency();
+ result->checkConsistency();
+
+ return result;
+ }
+
+ if (-bOffset == b->baseString->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())
+ return 0;
+ copyChars(b->data() - aSize, a->data(), aSize);
+ PassRefPtr<UString::Rep> result = UString::Rep::create(b, -aSize, length);
+
+ a->checkConsistency();
+ b->checkConsistency();
+ result->checkConsistency();
+
+ return result;
+ }
+
// a does not qualify for append, and b does not qualify for prepend, gotta make a whole new string
size_t newCapacity = expandedSize(length, 0);
UChar* d = allocChars(newCapacity);
if (!d)
- m_rep = &Rep::null;
+ return 0;
+ copyChars(d, a->data(), aSize);
+ copyChars(d + aSize, b->data(), bSize);
+ PassRefPtr<UString::Rep> result = UString::Rep::create(d, length);
+ result->capacity = newCapacity;
+
+ a->checkConsistency();
+ b->checkConsistency();
+ result->checkConsistency();
+
+ return result;
+}
+
+PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, int i)
+{
+ UChar buf[1 + sizeof(i) * 3];
+ UChar* end = buf + sizeof(buf) / sizeof(UChar);
+ UChar* p = end;
+
+ if (i == 0)
+ *--p = '0';
+ else if (i == INT_MIN) {
+ char minBuf[1 + sizeof(i) * 3];
+ sprintf(minBuf, "%d", INT_MIN);
+ return concatenate(rep, minBuf);
+ } else {
+ bool negative = false;
+ if (i < 0) {
+ negative = true;
+ i = -i;
+ }
+ while (i) {
+ *--p = static_cast<unsigned short>((i % 10) + '0');
+ i /= 10;
+ }
+ if (negative)
+ *--p = '-';
+ }
+
+ return concatenate(rep, p, static_cast<int>(end - p));
+
+}
+
+PassRefPtr<UString::Rep> concatenate(UString::Rep* rep, double d)
+{
+ // avoid ever printing -NaN, in JS conceptually there is only one NaN value
+ if (isnan(d))
+ return concatenate(rep, "NaN");
+
+ if (d == 0.0) // stringify -0 as 0
+ d = 0.0;
+
+ char buf[80];
+ int decimalPoint;
+ int sign;
+
+ char* result = dtoa(d, 0, &decimalPoint, &sign, NULL);
+ int length = static_cast<int>(strlen(result));
+
+ int i = 0;
+ if (sign)
+ buf[i++] = '-';
+
+ if (decimalPoint <= 0 && decimalPoint > -6) {
+ buf[i++] = '0';
+ buf[i++] = '.';
+ for (int j = decimalPoint; j < 0; j++)
+ buf[i++] = '0';
+ strcpy(buf + i, result);
+ } else if (decimalPoint <= 21 && decimalPoint > 0) {
+ if (length <= decimalPoint) {
+ strcpy(buf + i, result);
+ i += length;
+ for (int j = 0; j < decimalPoint - length; j++)
+ buf[i++] = '0';
+ buf[i] = '\0';
+ } else {
+ strncpy(buf + i, result, decimalPoint);
+ i += decimalPoint;
+ buf[i++] = '.';
+ strcpy(buf + i, result + decimalPoint);
+ }
+ } else if (result[0] < '0' || result[0] > '9')
+ strcpy(buf + i, result);
else {
- 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;
+ 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';
}
- }
+
+ freedtoa(result);
+
+ return concatenate(rep, buf);
}
const UString& UString::null()
{
- static UString* n = new UString;
- return *n;
+ static UString* n = new UString; // Should be called from main thread at least once to be safely initialized.
+ return *n;
}
UString UString::from(int i)
{
- UChar buf[1 + sizeof(i) * 3];
- UChar *end = buf + sizeof(buf) / sizeof(UChar);
- UChar *p = end;
+ 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 = '-';
+ if (i == 0)
+ *--p = '0';
+ else if (i == INT_MIN) {
+ char minBuf[1 + sizeof(i) * 3];
+ sprintf(minBuf, "%d", INT_MIN);
+ return UString(minBuf);
+ } else {
+ bool negative = false;
+ if (i < 0) {
+ negative = true;
+ i = -i;
+ }
+ while (i) {
+ *--p = static_cast<unsigned short>((i % 10) + '0');
+ i /= 10;
+ }
+ if (negative)
+ *--p = '-';
}
- }
-
- return UString(p, static_cast<int>(end - p));
+
+ 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;
+ UChar buf[sizeof(u) * 3];
+ UChar* end = buf + sizeof(buf) / sizeof(UChar);
+ UChar* p = end;
+
+ if (u == 0)
+ *--p = '0';
+ else {
+ while (u) {
+ *--p = static_cast<unsigned short>((u % 10) + '0');
+ u /= 10;
+ }
}
- }
-
- return UString(p, static_cast<int>(end - p));
+
+ 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 = '-';
+ UChar buf[1 + sizeof(l) * 3];
+ UChar* end = buf + sizeof(buf) / sizeof(UChar);
+ UChar* p = end;
+
+ if (l == 0)
+ *--p = '0';
+ else if (l == LONG_MIN) {
+ char minBuf[1 + sizeof(l) * 3];
+ sprintf(minBuf, "%ld", LONG_MIN);
+ return UString(minBuf);
+ } else {
+ bool negative = false;
+ if (l < 0) {
+ negative = true;
+ l = -l;
+ }
+ while (l) {
+ *--p = static_cast<unsigned short>((l % 10) + '0');
+ l /= 10;
+ }
+ if (negative)
+ *--p = '-';
}
- }
-
- return UString(p, static_cast<int>(end - p));
+
+ 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";
+ // 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));
+ char buf[80];
+ int decimalPoint;
+ int sign;
+
+ char* result = dtoa(d, 0, &decimalPoint, &sign, NULL);
+ int length = static_cast<int>(strlen(result));
- int i = 0;
- if (sign) {
- buf[i++] = '-';
- }
+ 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++) {
+ if (decimalPoint <= 0 && decimalPoint > -6) {
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++] = '.';
+ 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';
}
- 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);
-
+ 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;
+ m_rep->checkConsistency();
+
+ if (rangeCount == 1 && separatorCount == 0) {
+ int thisSize = size();
+ int position = substringRanges[0].position;
+ int length = substringRanges[0].length;
+ if (position <= 0 && length >= thisSize)
+ return *this;
+ return UString::Rep::create(m_rep, max(0, position), min(thisSize, length));
}
- } 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;
+
+ int totalLength = 0;
+ for (int i = 0; i < rangeCount; i++)
+ totalLength += substringRanges[i].length;
+ for (int i = 0; i < separatorCount; i++)
+ totalLength += separators[i].size();
+
+ if (totalLength == 0)
+ return "";
+
+ UChar* buffer = allocChars(totalLength);
+ if (!buffer)
+ return null();
+
+ int maxCount = max(rangeCount, separatorCount);
+ int bufferPos = 0;
+ for (int i = 0; i < maxCount; i++) {
+ if (i < rangeCount) {
+ copyChars(buffer + bufferPos, data() + substringRanges[i].position, substringRanges[i].length);
+ bufferPos += substringRanges[i].length;
+ }
+ if (i < separatorCount) {
+ copyChars(buffer + bufferPos, separators[i].data(), separators[i].size());
+ bufferPos += separators[i].size();
+ }
}
- }
- return *this;
+ return UString::Rep::create(buffer, totalLength);
}
-UString &UString::append(unsigned short c)
+UString& UString::append(const UString &t)
{
- int thisOffset = m_rep->offset;
- int length = size();
+ m_rep->checkConsistency();
+ t.rep()->checkConsistency();
- // 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);
+ 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()) {
+ copyChars(m_rep->data() + thisSize, t.data(), tSize);
+ 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()) {
+ copyChars(m_rep->data() + thisSize, t.data(), tSize);
+ 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)
+ makeNull();
+ else {
+ copyChars(d, data(), thisSize);
+ copyChars(d + thisSize, t.data(), tSize);
+ m_rep = Rep::create(d, length);
+ m_rep->capacity = newCapacity;
+ }
}
- } 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;
+
+ m_rep->checkConsistency();
+ t.rep()->checkConsistency();
+
+ return *this;
+}
+
+UString& UString::append(const UChar* tData, int tSize)
+{
+ m_rep = concatenate(m_rep.release(), tData, tSize);
+ return *this;
+}
+
+UString& UString::append(const char* t)
+{
+ m_rep = concatenate(m_rep.release(), t);
+ return *this;
+}
+
+UString& UString::append(UChar c)
+{
+ m_rep->checkConsistency();
+
+ int thisOffset = m_rep->offset;
+ int length = size();
+
+ // possible cases:
+ if (length == 0) {
+ // this is empty - must make a new m_rep because we don't want to pollute the shared empty one
+ size_t newCapacity = expandedSize(1, 0);
+ UChar* d = allocChars(newCapacity);
+ if (!d)
+ makeNull();
+ else {
+ d[0] = c;
+ m_rep = Rep::create(d, 1);
+ m_rep->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 = m_rep->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 = m_rep->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)
+ makeNull();
+ else {
+ copyChars(d, data(), length);
+ d[length] = c;
+ m_rep = Rep::create(d, length + 1);
+ m_rep->capacity = newCapacity;
+ }
}
- }
- return *this;
+ m_rep->checkConsistency();
+
+ return *this;
}
-CString UString::cstring() const
+bool UString::getCString(CStringBuffer& buffer) const
{
- return ascii();
+ int length = size();
+ int neededSize = length + 1;
+ buffer.resize(neededSize);
+ char* buf = buffer.data();
+
+ UChar ored = 0;
+ const UChar* p = data();
+ char* q = buf;
+ const UChar* limit = p + length;
+ while (p != limit) {
+ UChar c = p[0];
+ ored |= c;
+ *q = static_cast<char>(c);
+ ++p;
+ ++q;
+ }
+ *q = '\0';
+
+ return !(ored & 0xFF00);
}
-char *UString::ascii() const
+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';
+ int length = size();
+ int neededSize = length + 1;
+ delete[] statBuffer;
+ statBuffer = new char[neededSize];
+
+ const UChar* p = data();
+ char* q = statBuffer;
+ const UChar* limit = p + length;
+ while (p != limit) {
+ *q = static_cast<char>(p[0]);
+ ++p;
+ ++q;
+ }
+ *q = '\0';
- return statBuffer;
+ return statBuffer;
}
-UString &UString::operator=(const char *c)
+UString& UString::operator=(const char* c)
{
if (!c) {
m_rep = &Rep::null;
@@ -900,386 +1194,445 @@ UString &UString::operator=(const char *c)
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;
+ 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) {
+ makeNull();
+ return *this;
+ }
+ m_rep = Rep::create(d, l);
}
- m_rep = Rep::create(d, l);
- }
- for (int i = 0; i < l; i++)
- d[i].uc = c[i];
+ for (int i = 0; i < l; i++)
+ d[i] = static_cast<unsigned char>(c[i]); // use unsigned char to zero-extend instead of sign-extend
- return *this;
+ 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;
- }
+ const UChar* u = data();
+ const UChar* limit = u + size();
+ while (u < limit) {
+ if (u[0] > 0xFF)
+ return false;
+ ++u;
+ }
- return true;
+ return true;
}
-const UChar UString::operator[](int pos) const
+UChar UString::operator[](int pos) const
{
- if (pos >= size())
- return '\0';
- return data()[pos];
+ 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 (size() == 1) {
+ UChar c = data()[0];
+ if (isASCIIDigit(c))
+ return c - '0';
+ if (isASCIISpace(c) && tolerateEmptyString)
+ return 0;
+ return NaN;
}
- 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;
+ // FIXME: If tolerateTrailingJunk is true, then we want to tolerate non-8-bit junk
+ // after the number, so this is too strict a check.
+ CStringBuffer s;
+ if (!getCString(s))
+ return NaN;
+ const char* c = s.data();
- if (*c == '+')
+ // skip leading white space
+ while (isASCIISpace(*c))
c++;
- else if (*c == '-') {
- sign = -1.0;
+
+ // empty string ?
+ if (*c == '\0')
+ return tolerateEmptyString ? 0.0 : NaN;
+
+ double d;
+
+ // hex number ?
+ if (*c == '0' && (*(c + 1) == 'x' || *(c + 1) == 'X')) {
+ const char* firstDigitPosition = c + 2;
c++;
- }
-
- // 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;
+ 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 = 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;
+ // allow trailing white space
+ while (isASCIISpace(*c))
+ c++;
+ // don't allow anything after - unless tolerant=true
+ if (!tolerateTrailingJunk && *c != '\0')
+ d = NaN;
- return d;
+ return d;
}
double UString::toDouble(bool tolerateTrailingJunk) const
{
- return toDouble(tolerateTrailingJunk, true);
+ return toDouble(tolerateTrailingJunk, true);
}
double UString::toDouble() const
{
- return toDouble(false, true);
+ return toDouble(false, true);
}
-uint32_t UString::toUInt32(bool *ok) const
+uint32_t UString::toUInt32(bool* ok) const
{
- double d = toDouble();
- bool b = true;
+ double d = toDouble();
+ bool b = true;
- if (d != static_cast<uint32_t>(d)) {
- b = false;
- d = 0;
- }
+ if (d != static_cast<uint32_t>(d)) {
+ b = false;
+ d = 0;
+ }
- if (ok)
- *ok = b;
+ if (ok)
+ *ok = b;
- return static_cast<uint32_t>(d);
+ return static_cast<uint32_t>(d);
}
-uint32_t UString::toUInt32(bool *ok, bool tolerateEmptyString) const
+uint32_t UString::toUInt32(bool* ok, bool tolerateEmptyString) const
{
- double d = toDouble(false, tolerateEmptyString);
- bool b = true;
+ double d = toDouble(false, tolerateEmptyString);
+ bool b = true;
- if (d != static_cast<uint32_t>(d)) {
- b = false;
- d = 0;
- }
+ if (d != static_cast<uint32_t>(d)) {
+ b = false;
+ d = 0;
+ }
- if (ok)
- *ok = b;
+ if (ok)
+ *ok = b;
- return static_cast<uint32_t>(d);
+ return static_cast<uint32_t>(d);
}
-uint32_t UString::toStrictUInt32(bool *ok) const
+uint32_t UString::toStrictUInt32(bool* ok) const
{
- if (ok)
- *ok = false;
+ 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();
+ // Empty string is not OK.
+ int len = m_rep->len;
+ if (len == 0)
+ return 0;
+ const UChar* p = m_rep->data();
+ unsigned short c = p[0];
- // If the first digit is 0, only 0 itself is OK.
- if (c == '0') {
- if (len == 1 && ok)
- *ok = true;
- return 0;
- }
-
- // Convert to UInt32, checking for overflow.
- uint32_t i = 0;
- while (1) {
- // Process character, turning it into a digit.
- if (c < '0' || c > '9')
- return 0;
- const unsigned d = c - '0';
-
- // Multiply by 10, checking for overflow out of 32 bits.
- if (i > 0xFFFFFFFFU / 10)
- return 0;
- i *= 10;
-
- // Add in the digit, checking for overflow out of 32 bits.
- const unsigned max = 0xFFFFFFFFU - d;
- if (i > max)
+ // If the first digit is 0, only 0 itself is OK.
+ if (c == '0') {
+ if (len == 1 && ok)
+ *ok = true;
return 0;
- i += d;
-
- // Handle end of string.
- if (--len == 0) {
- if (ok)
- *ok = true;
- return i;
}
-
- // Get next character.
- c = (++p)->unicode();
- }
+
+ // Convert to UInt32, checking for overflow.
+ uint32_t i = 0;
+ while (1) {
+ // Process character, turning it into a digit.
+ if (c < '0' || c > '9')
+ return 0;
+ const unsigned d = c - '0';
+
+ // Multiply by 10, checking for overflow out of 32 bits.
+ if (i > 0xFFFFFFFFU / 10)
+ return 0;
+ i *= 10;
+
+ // Add in the digit, checking for overflow out of 32 bits.
+ const unsigned max = 0xFFFFFFFFU - d;
+ if (i > max)
+ return 0;
+ i += d;
+
+ // Handle end of string.
+ if (--len == 0) {
+ if (ok)
+ *ok = true;
+ return i;
+ }
+
+ // Get next character.
+ c = *(++p);
+ }
}
-int UString::find(const UString &f, int pos) const
+int UString::find(const UString& f, int pos) const
{
- int sz = size();
- int fsz = f.size();
- if (sz < fsz)
+ 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[0];
+ ++fdata;
+ for (const UChar* c = data() + pos; c <= end; c++) {
+ if (c[0] == fchar && !memcmp(c + 1, fdata, fsizeminusone))
+ return static_cast<int>(c - data());
+ }
+
return -1;
- 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;
+ 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 UString::rfind(const UString& f, int pos) const
{
- int sz = size();
- int fsz = f.size();
- if (sz < fsz)
+ 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;
- 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());
- }
+ 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;
+ 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;
+ 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));
+ 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);
+ int size = s1.size();
+ switch (size) {
+ case 0:
+ return !s2.size();
+ case 1:
+ return s2.size() == 1 && s1.data()[0] == s2.data()[0];
+ default:
+ return s2.size() == size && memcmp(s1.data(), s2.data(), size * 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++;
- }
+ if (s2 == 0)
+ return s1.isEmpty();
+
+ const UChar* u = s1.data();
+ const UChar* uend = u + s1.size();
+ while (u != uend && *s2) {
+ if (u[0] != (unsigned char)*s2)
+ return false;
+ s2++;
+ u++;
+ }
- return u == uend && *s2 == 0;
+ 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);
+ const int l1 = s1.size();
+ const int l2 = s2.size();
+ const int lmin = l1 < l2 ? l1 : l2;
+ const UChar* c1 = s1.data();
+ const UChar* c2 = s2.data();
+ int l = 0;
+ while (l < lmin && *c1 == *c2) {
+ c1++;
+ c2++;
+ l++;
+ }
+ if (l < lmin)
+ return (c1[0] < c2[0]);
- return (l1 < l2);
+ return (l1 < l2);
+}
+
+bool operator>(const UString& s1, const UString& s2)
+{
+ const int l1 = s1.size();
+ const int l2 = s2.size();
+ const int lmin = l1 < l2 ? l1 : l2;
+ const UChar* c1 = s1.data();
+ const UChar* c2 = s2.data();
+ int l = 0;
+ while (l < lmin && *c1 == *c2) {
+ c1++;
+ c2++;
+ l++;
+ }
+ if (l < lmin)
+ return (c1[0] > c2[0]);
+
+ return (l1 > l2);
}
int compare(const UString& s1, const UString& s2)
{
- const int l1 = s1.size();
- const int l2 = s2.size();
- const int lmin = l1 < l2 ? l1 : l2;
- const UChar *c1 = s1.data();
- const UChar *c2 = s2.data();
- int l = 0;
- while (l < lmin && *c1 == *c2) {
- c1++;
- c2++;
- l++;
- }
+ 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 (l < lmin)
+ return (c1[0] > c2[0]) ? 1 : -1;
+
+ if (l1 == l2)
+ return 0;
- if (l1 == l2)
- return 0;
+ return (l1 > l2) ? 1 : -1;
+}
- return (l1 > l2) ? 1 : -1;
+bool equal(const UString::Rep* r, const UString::Rep* b)
+{
+ int length = r->len;
+ if (length != b->len)
+ return false;
+ const UChar* d = r->data();
+ const UChar* s = b->data();
+ for (int i = 0; i != length; ++i) {
+ if (d[i] != s[i])
+ return false;
+ }
+ return true;
}
CString UString::UTF8String(bool strict) const
{
- // Allocate a buffer big enough to hold all the characters.
- const int length = size();
- Vector<char, 1024> buffer(length * 3);
+ // Allocate a buffer big enough to hold all the characters.
+ const int length = size();
+ Vector<char, 1024> buffer(length * 3);
+
+ // Convert to runs of 8-bit characters.
+ char* p = buffer.data();
+ const UChar* d = reinterpret_cast<const UChar*>(&data()[0]);
+ ConversionResult result = convertUTF16ToUTF8(&d, d + length, &p, p + buffer.size(), strict);
+ if (result != conversionOK)
+ return CString();
+
+ return CString(buffer.data(), p - buffer.data());
+}
- // 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();
+// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X.
+NEVER_INLINE void UString::makeNull()
+{
+ m_rep = &Rep::null;
+}
- return CString(buffer.data(), p - buffer.data());
+// For use in error handling code paths -- having this not be inlined helps avoid PIC branches to fetch the global on Mac OS X.
+NEVER_INLINE UString::Rep* UString::nullRep()
+{
+ return &Rep::null;
}
-} // namespace KJS
+} // namespace JSC
diff --git a/JavaScriptCore/kjs/ustring.h b/JavaScriptCore/kjs/ustring.h
index 7faa86a..f47b134 100644
--- a/JavaScriptCore/kjs/ustring.h
+++ b/JavaScriptCore/kjs/ustring.h
@@ -1,7 +1,6 @@
-// -*- 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) 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
@@ -23,448 +22,364 @@
#ifndef _KJS_USTRING_H_
#define _KJS_USTRING_H_
-#include "JSLock.h"
#include "collector.h"
#include <stdint.h>
+#include <string.h>
#include <wtf/Assertions.h>
#include <wtf/FastMalloc.h>
#include <wtf/PassRefPtr.h>
#include <wtf/RefPtr.h>
#include <wtf/Vector.h>
+#include <wtf/unicode/Unicode.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
+namespace JSC {
-/**
- * @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;
+ using WTF::PlacementNewAdoptType;
+ using WTF::PlacementNewAdopt;
+
+ class IdentifierTable;
+
+ class CString {
+ public:
+ CString()
+ : m_length(0)
+ , m_data(0)
+ {
+ }
+
+ CString(const char*);
+ CString(const char*, size_t);
+ CString(const CString&);
+
+ ~CString();
+
+ static CString adopt(char*, size_t); // buffer should be allocated with new[].
+
+ CString& append(const CString&);
+ CString& operator=(const char* c);
+ CString& operator=(const CString&);
+ CString& operator+=(const CString& c) { return append(c); }
+
+ size_t size() const { return m_length; }
+ const char* c_str() const { return m_data; }
+
+ private:
+ size_t m_length;
+ char* m_data;
};
- 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 {
+ typedef Vector<char, 32> CStringBuffer;
+
+ class UString {
+ friend class CTI;
+
public:
- Range(int pos, int len) : position(pos), length(len) {}
- Range() {}
- int position;
- int length;
+ struct Rep {
+ friend class CTI;
+
+ static PassRefPtr<Rep> create(UChar*, int);
+ static PassRefPtr<Rep> createCopying(const UChar*, int);
+ static PassRefPtr<Rep> create(PassRefPtr<Rep> base, int offset, int length);
+
+ // Constructs a string from a UTF-8 string, using strict conversion (see comments in UTF8.h).
+ // Returns UString::Rep::null for null input or conversion failure.
+ static PassRefPtr<Rep> createFromUTF8(const char*);
+
+ 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*, int length);
+ static unsigned computeHash(const char* s) { return computeHash(s, strlen(s)); }
+
+ IdentifierTable* identifierTable() const { return reinterpret_cast<IdentifierTable*>(m_identifierTable & ~static_cast<uintptr_t>(1)); }
+ void setIdentifierTable(IdentifierTable* table) { ASSERT(!isStatic()); m_identifierTable = reinterpret_cast<intptr_t>(table); }
+
+ bool isStatic() const { return m_identifierTable & 1; }
+ void setStatic(bool v) { ASSERT(!identifierTable()); m_identifierTable = v; }
+
+ Rep* ref() { ++rc; return this; }
+ ALWAYS_INLINE void deref() { if (--rc == 0) destroy(); }
+
+ void checkConsistency() const;
+
+ // unshared data
+ int offset;
+ int len;
+ int rc; // For null and empty static strings, this field does not reflect a correct count, because ref/deref are not thread-safe. A special case in destroy() guarantees that these do not get deleted.
+ mutable unsigned _hash;
+ intptr_t m_identifierTable; // A pointer to identifier table. The lowest bit is used to indicate whether the string is static (null or empty).
+ UString::Rep* baseString;
+ size_t reportedCost;
+
+ // potentially shared data. 0 if backed up by a base string.
+ UChar* buf;
+ int usedCapacity;
+ int capacity;
+ int usedPreCapacity;
+ int preCapacity;
+
+ static Rep null;
+ static Rep empty;
+ };
+
+ public:
+ UString();
+ UString(const char*);
+ UString(const UChar*, int length);
+ UString(UChar*, int length, bool copy);
+
+ UString(const UString& s)
+ : m_rep(s.m_rep)
+ {
+ }
+
+ UString(const Vector<UChar>& buffer);
+
+ ~UString()
+ {
+ }
+
+ // Special constructor for cases where we overwrite an object in place.
+ UString(PlacementNewAdoptType)
+ : m_rep(PlacementNewAdopt)
+ {
+ }
+
+ static UString from(int);
+ static UString from(unsigned int);
+ static UString from(long);
+ static UString from(double);
+
+ struct Range {
+ public:
+ Range(int pos, int len)
+ : position(pos)
+ , length(len)
+ {
+ }
+
+ Range()
+ {
+ }
+
+ int position;
+ int length;
+ };
+
+ UString spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const;
+
+ UString& append(const UString&);
+ UString& append(const char*);
+ UString& append(UChar);
+ UString& append(char c) { return append(static_cast<UChar>(static_cast<unsigned char>(c))); }
+ UString& append(const UChar*, int size);
+
+ bool getCString(CStringBuffer&) const;
+
+ // NOTE: This method should only be used for *debugging* purposes as it
+ // is neither Unicode safe nor free from side effects nor thread-safe.
+ char* ascii() const;
+
+ /**
+ * Convert the string to UTF-8, assuming it is UTF-16 encoded.
+ * In non-strict mode, this function is tolerant of badly formed UTF-16, it
+ * can create UTF-8 strings that are invalid because they have characters in
+ * the range U+D800-U+DDFF, U+FFFE, or U+FFFF, but the UTF-8 string is
+ * guaranteed to be otherwise valid.
+ * In strict mode, error is returned as null CString.
+ */
+ CString UTF8String(bool strict = false) const;
+
+ UString& operator=(const char*c);
+
+ UString& operator+=(const UString& s) { return append(s); }
+ UString& operator+=(const char* s) { return append(s); }
+
+ const UChar* data() const { return m_rep->data(); }
+
+ bool isNull() const { return (m_rep == &Rep::null); }
+ bool isEmpty() const { return (!m_rep->len); }
+
+ bool is8Bit() const;
+
+ int size() const { return m_rep->size(); }
+
+ UChar operator[](int pos) const;
+
+ double toDouble(bool tolerateTrailingJunk, bool tolerateEmptyString) const;
+ double toDouble(bool tolerateTrailingJunk) const;
+ double toDouble() const;
+
+ uint32_t toUInt32(bool* ok = 0) const;
+ uint32_t toUInt32(bool* ok, bool tolerateEmptyString) const;
+ uint32_t toStrictUInt32(bool* ok = 0) const;
+
+ unsigned toArrayIndex(bool* ok = 0) const;
+
+ int find(const UString& f, int pos = 0) const;
+ int find(UChar, int pos = 0) const;
+ int rfind(const UString& f, int pos) const;
+ int rfind(UChar, int pos) const;
+
+ UString substr(int pos = 0, int len = -1) const;
+
+ static const UString& null();
+
+ Rep* rep() const { return m_rep.get(); }
+ static Rep* nullRep();
+
+ UString(PassRefPtr<Rep> r)
+ : m_rep(r)
+ {
+ ASSERT(m_rep);
+ }
+
+ size_t cost() const;
+
+ private:
+ int usedCapacity() const;
+ int usedPreCapacity() const;
+ void expandCapacity(int requiredLength);
+ void expandPreCapacity(int requiredPreCap);
+ void makeNull();
+
+ RefPtr<Rep> m_rep;
+
+ friend bool operator==(const UString&, const UString&);
+ friend PassRefPtr<Rep> concatenate(Rep*, Rep*); // returns 0 if out of memory
};
+ PassRefPtr<UString::Rep> concatenate(UString::Rep*, UString::Rep*);
+ PassRefPtr<UString::Rep> concatenate(UString::Rep*, int);
+ PassRefPtr<UString::Rep> concatenate(UString::Rep*, double);
- 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
+ bool operator==(const UString&, const UString&);
+
+ inline bool operator!=(const UString& s1, const UString& s2)
+ {
+ return !JSC::operator==(s1, s2);
+ }
+
+ bool operator<(const UString& s1, const UString& s2);
+ bool operator>(const UString& s1, const UString& s2);
+
+ bool operator==(const UString& s1, const char* s2);
+
+ inline bool operator!=(const UString& s1, const char* s2)
+ {
+ return !JSC::operator==(s1, s2);
+ }
+
+ inline bool operator==(const char *s1, const UString& s2)
+ {
+ return operator==(s2, s1);
+ }
+
+ inline bool operator!=(const char *s1, const UString& s2)
+ {
+ return !JSC::operator==(s1, s2);
+ }
+
+ bool operator==(const CString&, const CString&);
+
+ inline UString operator+(const UString& s1, const UString& s2)
+ {
+ RefPtr<UString::Rep> result = concatenate(s1.rep(), s2.rep());
+ return UString(result ? result.release() : UString::nullRep());
+ }
+
+ int compare(const UString&, const UString&);
+
+ bool equal(const UString::Rep*, const UString::Rep*);
+
+#ifdef NDEBUG
+ inline void UString::Rep::checkConsistency() const
+ {
+ }
+#endif
+
+ inline UString::UString()
+ : m_rep(&Rep::null)
+ {
+ }
+
+ // Rule from ECMA 15.2 about what an array index is.
+ // Must exactly match string form of an unsigned integer, and be less than 2^32 - 1.
+ inline unsigned UString::toArrayIndex(bool* ok) const
+ {
+ unsigned i = toStrictUInt32(ok);
+ if (ok && i >= 0xFFFFFFFFU)
+ *ok = false;
+ return i;
+ }
+
+ // We'd rather not do shared substring append for small strings, since
+ // this runs too much risk of a tiny initial string holding down a
+ // huge buffer.
+ // FIXME: this should be size_t but that would cause warnings until we
+ // fix UString sizes to be size_t instead of int
+ static const int minShareSize = Heap::minExtraCostSize / sizeof(UChar);
+
+ inline size_t UString::cost() const
+ {
+ 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;
+ }
+
+ struct IdentifierRepHash : PtrHash<RefPtr<JSC::UString::Rep> > {
+ static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->computedHash(); }
+ static unsigned hash(JSC::UString::Rep* key) { return key->computedHash(); }
+ };
+
+} // namespace JSC
+
+namespace WTF {
+
+ template<typename T> struct DefaultHash;
+ template<typename T> struct StrHash;
+
+ template<> struct StrHash<JSC::UString::Rep*> {
+ static unsigned hash(const JSC::UString::Rep* key) { return key->hash(); }
+ static bool equal(const JSC::UString::Rep* a, const JSC::UString::Rep* b) { return JSC::equal(a, b); }
+ static const bool safeToCompareToEmptyOrDeleted = false;
+ };
+
+ template<> struct StrHash<RefPtr<JSC::UString::Rep> > : public StrHash<JSC::UString::Rep*> {
+ using StrHash<JSC::UString::Rep*>::hash;
+ static unsigned hash(const RefPtr<JSC::UString::Rep>& key) { return key->hash(); }
+ using StrHash<JSC::UString::Rep*>::equal;
+ static bool equal(const RefPtr<JSC::UString::Rep>& a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a.get(), b.get()); }
+ static bool equal(const JSC::UString::Rep* a, const RefPtr<JSC::UString::Rep>& b) { return JSC::equal(a, b.get()); }
+ static bool equal(const RefPtr<JSC::UString::Rep>& a, const JSC::UString::Rep* b) { return JSC::equal(a.get(), b); }
+
+ static const bool safeToCompareToEmptyOrDeleted = false;
+ };
+
+ template<> struct DefaultHash<JSC::UString::Rep*> {
+ typedef StrHash<JSC::UString::Rep*> Hash;
+ };
+
+ template<> struct DefaultHash<RefPtr<JSC::UString::Rep> > {
+ typedef StrHash<RefPtr<JSC::UString::Rep> > Hash;
+
+ };
+
+} // namespace WTF
#endif
diff --git a/JavaScriptCore/kjs/value.cpp b/JavaScriptCore/kjs/value.cpp
deleted file mode 100644
index 55da40b..0000000
--- a/JavaScriptCore/kjs/value.cpp
+++ /dev/null
@@ -1,232 +0,0 @@
-/*
- * 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
deleted file mode 100644
index 5ebb575..0000000
--- a/JavaScriptCore/kjs/value.h
+++ /dev/null
@@ -1,523 +0,0 @@
-/*
- * 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