diff options
Diffstat (limited to 'JavaScriptCore')
338 files changed, 24426 insertions, 9304 deletions
diff --git a/JavaScriptCore/API/APICast.h b/JavaScriptCore/API/APICast.h index b6d1532..4284c44 100644 --- a/JavaScriptCore/API/APICast.h +++ b/JavaScriptCore/API/APICast.h @@ -27,6 +27,7 @@ #define APICast_h #include "JSAPIValueWrapper.h" +#include "JSGlobalObject.h" #include "JSValue.h" #include <wtf/Platform.h> #include <wtf/UnusedParam.h> @@ -50,16 +51,20 @@ typedef struct OpaqueJSValue* JSObjectRef; inline JSC::ExecState* toJS(JSContextRef c) { + ASSERT(c); return reinterpret_cast<JSC::ExecState*>(const_cast<OpaqueJSContext*>(c)); } inline JSC::ExecState* toJS(JSGlobalContextRef c) { + ASSERT(c); return reinterpret_cast<JSC::ExecState*>(c); } -inline JSC::JSValue toJS(JSC::ExecState*, JSValueRef v) +inline JSC::JSValue toJS(JSC::ExecState* exec, JSValueRef v) { + ASSERT_UNUSED(exec, exec); + ASSERT(v); #if USE(JSVALUE32_64) JSC::JSCell* jsCell = reinterpret_cast<JSC::JSCell*>(const_cast<OpaqueJSValue*>(v)); if (!jsCell) @@ -72,6 +77,20 @@ inline JSC::JSValue toJS(JSC::ExecState*, JSValueRef v) #endif } +inline JSC::JSValue toJSForGC(JSC::ExecState* exec, JSValueRef v) +{ + ASSERT_UNUSED(exec, exec); + ASSERT(v); +#if USE(JSVALUE32_64) + JSC::JSCell* jsCell = reinterpret_cast<JSC::JSCell*>(const_cast<OpaqueJSValue*>(v)); + if (!jsCell) + return JSC::JSValue(); + return jsCell; +#else + return JSC::JSValue::decode(reinterpret_cast<JSC::EncodedJSValue>(const_cast<OpaqueJSValue*>(v))); +#endif +} + inline JSC::JSObject* toJS(JSObjectRef o) { return reinterpret_cast<JSC::JSObject*>(o); @@ -118,6 +137,7 @@ inline JSContextRef toRef(JSC::ExecState* e) inline JSGlobalContextRef toGlobalRef(JSC::ExecState* e) { + ASSERT(e == e->lexicalGlobalObject()->globalExec()); return reinterpret_cast<JSGlobalContextRef>(e); } diff --git a/JavaScriptCore/API/JSBase.h b/JavaScriptCore/API/JSBase.h index 9f3d88e..d1ce9b3 100644 --- a/JavaScriptCore/API/JSBase.h +++ b/JavaScriptCore/API/JSBase.h @@ -67,7 +67,7 @@ typedef struct OpaqueJSValue* JSObjectRef; #undef JS_EXPORT #if defined(BUILDING_WX__) #define JS_EXPORT -#elif defined(__GNUC__) +#elif defined(__GNUC__) && !defined(__CC_ARM) && !defined(__ARMCC__) #define JS_EXPORT __attribute__((visibility("default"))) #elif defined(_WIN32_WCE) #if defined(JS_BUILDING_JS) diff --git a/JavaScriptCore/API/JSCallbackConstructor.cpp b/JavaScriptCore/API/JSCallbackConstructor.cpp index 64c83cb..1c33962 100644 --- a/JavaScriptCore/API/JSCallbackConstructor.cpp +++ b/JavaScriptCore/API/JSCallbackConstructor.cpp @@ -36,7 +36,7 @@ namespace JSC { const ClassInfo JSCallbackConstructor::info = { "CallbackConstructor", 0, 0, 0 }; -JSCallbackConstructor::JSCallbackConstructor(PassRefPtr<Structure> structure, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback) +JSCallbackConstructor::JSCallbackConstructor(NonNullPassRefPtr<Structure> structure, JSClassRef jsClass, JSObjectCallAsConstructorCallback callback) : JSObject(structure) , m_class(jsClass) , m_callback(callback) diff --git a/JavaScriptCore/API/JSCallbackConstructor.h b/JavaScriptCore/API/JSCallbackConstructor.h index 1f06249..c4bd7ad 100644 --- a/JavaScriptCore/API/JSCallbackConstructor.h +++ b/JavaScriptCore/API/JSCallbackConstructor.h @@ -33,7 +33,7 @@ namespace JSC { class JSCallbackConstructor : public JSObject { public: - JSCallbackConstructor(PassRefPtr<Structure>, JSClassRef, JSObjectCallAsConstructorCallback); + JSCallbackConstructor(NonNullPassRefPtr<Structure>, JSClassRef, JSObjectCallAsConstructorCallback); virtual ~JSCallbackConstructor(); JSClassRef classRef() const { return m_class; } JSObjectCallAsConstructorCallback callback() const { return m_callback; } @@ -41,9 +41,12 @@ public: static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } +protected: + static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags; + private: virtual ConstructType getConstructData(ConstructData&); virtual const ClassInfo* classInfo() const { return &info; } diff --git a/JavaScriptCore/API/JSCallbackFunction.cpp b/JavaScriptCore/API/JSCallbackFunction.cpp index 1b3217b..b7dd768 100644 --- a/JavaScriptCore/API/JSCallbackFunction.cpp +++ b/JavaScriptCore/API/JSCallbackFunction.cpp @@ -28,6 +28,7 @@ #include "JSCallbackFunction.h" #include "APICast.h" +#include "CodeBlock.h" #include "JSFunction.h" #include "FunctionPrototype.h" #include <runtime/JSGlobalObject.h> diff --git a/JavaScriptCore/API/JSCallbackFunction.h b/JavaScriptCore/API/JSCallbackFunction.h index 7dd87b5..0cf25c4 100644 --- a/JavaScriptCore/API/JSCallbackFunction.h +++ b/JavaScriptCore/API/JSCallbackFunction.h @@ -41,7 +41,7 @@ public: // refactor the code so this override isn't necessary static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } private: diff --git a/JavaScriptCore/API/JSCallbackObject.h b/JavaScriptCore/API/JSCallbackObject.h index 9d22ad9..d19890a 100644 --- a/JavaScriptCore/API/JSCallbackObject.h +++ b/JavaScriptCore/API/JSCallbackObject.h @@ -36,7 +36,7 @@ namespace JSC { template <class Base> class JSCallbackObject : public Base { public: - JSCallbackObject(ExecState*, PassRefPtr<Structure>, JSClassRef, void* data); + JSCallbackObject(ExecState*, NonNullPassRefPtr<Structure>, JSClassRef, void* data); JSCallbackObject(JSClassRef); virtual ~JSCallbackObject(); @@ -50,9 +50,12 @@ public: static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | OverridesHasInstance)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } +protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | Base::StructureFlags; + private: virtual UString className() const; @@ -66,7 +69,7 @@ private: virtual bool hasInstance(ExecState* exec, JSValue value, JSValue proto); - virtual void getPropertyNames(ExecState*, PropertyNameArray&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&); virtual double toNumber(ExecState*) const; virtual UString toString(ExecState*) const; diff --git a/JavaScriptCore/API/JSCallbackObjectFunctions.h b/JavaScriptCore/API/JSCallbackObjectFunctions.h index 1abed3f..ed86a00 100644 --- a/JavaScriptCore/API/JSCallbackObjectFunctions.h +++ b/JavaScriptCore/API/JSCallbackObjectFunctions.h @@ -47,7 +47,7 @@ inline JSCallbackObject<Base>* JSCallbackObject<Base>::asCallbackObject(JSValue } template <class Base> -JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, PassRefPtr<Structure> structure, JSClassRef jsClass, void* data) +JSCallbackObject<Base>::JSCallbackObject(ExecState* exec, NonNullPassRefPtr<Structure> structure, JSClassRef jsClass, void* data) : Base(structure) , m_callbackObjectData(new JSCallbackObjectData(data, jsClass)) { @@ -131,15 +131,15 @@ bool JSCallbackObject<Base>::getOwnPropertySlot(ExecState* exec, const Identifie JSLock::DropAllLocks dropAllLocks(exec); value = getProperty(ctx, thisRef, propertyNameRef.get(), &exception); } - exec->setException(toJS(exec, exception)); - if (value) { - slot.setValue(toJS(exec, value)); - return true; - } if (exception) { + exec->setException(toJS(exec, exception)); slot.setValue(jsUndefined()); return true; } + if (value) { + slot.setValue(toJS(exec, value)); + return true; + } } if (OpaqueJSClassStaticValuesTable* staticValues = jsClass->staticValues(exec)) { @@ -184,7 +184,8 @@ void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName JSLock::DropAllLocks dropAllLocks(exec); result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); } - exec->setException(toJS(exec, exception)); + if (exception) + exec->setException(toJS(exec, exception)); if (result || exception) return; } @@ -202,7 +203,8 @@ void JSCallbackObject<Base>::put(ExecState* exec, const Identifier& propertyName JSLock::DropAllLocks dropAllLocks(exec); result = setProperty(ctx, thisRef, propertyNameRef.get(), valueRef, &exception); } - exec->setException(toJS(exec, exception)); + if (exception) + exec->setException(toJS(exec, exception)); if (result || exception) return; } else @@ -240,7 +242,8 @@ bool JSCallbackObject<Base>::deleteProperty(ExecState* exec, const Identifier& p JSLock::DropAllLocks dropAllLocks(exec); result = deleteProperty(ctx, thisRef, propertyNameRef.get(), &exception); } - exec->setException(toJS(exec, exception)); + if (exception) + exec->setException(toJS(exec, exception)); if (result || exception) return true; } @@ -301,7 +304,8 @@ JSObject* JSCallbackObject<Base>::construct(ExecState* exec, JSObject* construct JSLock::DropAllLocks dropAllLocks(exec); result = toJS(callAsConstructor(execRef, constructorRef, argumentCount, arguments.data(), &exception)); } - exec->setException(toJS(exec, exception)); + if (exception) + exec->setException(toJS(exec, exception)); return result; } } @@ -325,7 +329,8 @@ bool JSCallbackObject<Base>::hasInstance(ExecState* exec, JSValue value, JSValue JSLock::DropAllLocks dropAllLocks(exec); result = hasInstance(execRef, thisRef, valueRef, &exception); } - exec->setException(toJS(exec, exception)); + if (exception) + exec->setException(toJS(exec, exception)); return result; } } @@ -363,7 +368,8 @@ JSValue JSCallbackObject<Base>::call(ExecState* exec, JSObject* functionObject, JSLock::DropAllLocks dropAllLocks(exec); result = toJS(exec, callAsFunction(execRef, functionRef, thisObjRef, argumentCount, arguments.data(), &exception)); } - exec->setException(toJS(exec, exception)); + if (exception) + exec->setException(toJS(exec, exception)); return result; } } @@ -373,7 +379,7 @@ JSValue JSCallbackObject<Base>::call(ExecState* exec, JSObject* functionObject, } template <class Base> -void JSCallbackObject<Base>::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void JSCallbackObject<Base>::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { JSContextRef execRef = toRef(exec); JSObjectRef thisRef = toRef(this); @@ -407,7 +413,7 @@ void JSCallbackObject<Base>::getPropertyNames(ExecState* exec, PropertyNameArray } } - Base::getPropertyNames(exec, propertyNames); + Base::getOwnPropertyNames(exec, propertyNames); } template <class Base> @@ -435,7 +441,8 @@ double JSCallbackObject<Base>::toNumber(ExecState* exec) const } double dValue; - return toJS(exec, value).getNumber(dValue) ? dValue : NaN; + if (value) + return toJS(exec, value).getNumber(dValue) ? dValue : NaN; } return Base::toNumber(exec); @@ -459,7 +466,8 @@ UString JSCallbackObject<Base>::toString(ExecState* exec) const exec->setException(toJS(exec, exception)); return ""; } - return toJS(exec, value).getString(); + if (value) + return toJS(exec, value).getString(exec); } return Base::toString(exec); @@ -507,13 +515,14 @@ JSValue JSCallbackObject<Base>::staticValueGetter(ExecState* exec, const Identif JSLock::DropAllLocks dropAllLocks(exec); value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); } - exec->setException(toJS(exec, exception)); + if (exception) { + exec->setException(toJS(exec, exception)); + return jsUndefined(); + } if (value) return toJS(exec, value); - if (exception) - return jsUndefined(); } - + return throwError(exec, ReferenceError, "Static value property defined with NULL getProperty callback."); } @@ -560,11 +569,12 @@ JSValue JSCallbackObject<Base>::callbackGetter(ExecState* exec, const Identifier JSLock::DropAllLocks dropAllLocks(exec); value = getProperty(toRef(exec), thisRef, propertyNameRef.get(), &exception); } - exec->setException(toJS(exec, exception)); + if (exception) { + exec->setException(toJS(exec, exception)); + return jsUndefined(); + } if (value) return toJS(exec, value); - if (exception) - return jsUndefined(); } return throwError(exec, ReferenceError, "hasProperty callback returned true for a property that doesn't exist."); diff --git a/JavaScriptCore/API/JSContextRef.cpp b/JavaScriptCore/API/JSContextRef.cpp index c358a84..e6626b7 100644 --- a/JavaScriptCore/API/JSContextRef.cpp +++ b/JavaScriptCore/API/JSContextRef.cpp @@ -25,6 +25,7 @@ #include "config.h" #include "JSContextRef.h" +#include "JSContextRefPrivate.h" #include "APICast.h" #include "InitializeThreading.h" @@ -152,3 +153,12 @@ JSContextGroupRef JSContextGetGroup(JSContextRef ctx) ExecState* exec = toJS(ctx); return toRef(&exec->globalData()); } + +JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx) +{ + ExecState* exec = toJS(ctx); + exec->globalData().heap.registerThread(); + JSLock lock(exec); + + return toGlobalRef(exec->lexicalGlobalObject()->globalExec()); +} diff --git a/JavaScriptCore/API/JSContextRefPrivate.h b/JavaScriptCore/API/JSContextRefPrivate.h new file mode 100644 index 0000000..ff014ec --- /dev/null +++ b/JavaScriptCore/API/JSContextRefPrivate.h @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2009 Apple Computer, 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 JSContextRefPrivate_h +#define JSContextRefPrivate_h + +#include <JavaScriptCore/JSObjectRef.h> +#include <JavaScriptCore/JSValueRef.h> +#include <JavaScriptCore/WebKitAvailability.h> + +#ifndef __cplusplus +#include <stdbool.h> +#endif + +#ifdef __cplusplus +extern "C" { +#endif + +/*! +@function +@abstract Gets the global context of a JavaScript execution context. +@param ctx The JSContext whose global context you want to get. +@result ctx's global context. +*/ +JS_EXPORT JSGlobalContextRef JSContextGetGlobalContext(JSContextRef ctx); + +#ifdef __cplusplus +} +#endif + +#endif /* JSContextRefPrivate_h */ diff --git a/JavaScriptCore/API/JSObjectRef.cpp b/JavaScriptCore/API/JSObjectRef.cpp index 87d36ec..06ef578 100644 --- a/JavaScriptCore/API/JSObjectRef.cpp +++ b/JavaScriptCore/API/JSObjectRef.cpp @@ -28,6 +28,7 @@ #include "JSObjectRef.h" #include "APICast.h" +#include "CodeBlock.h" #include "DateConstructor.h" #include "ErrorConstructor.h" #include "FunctionConstructor.h" diff --git a/JavaScriptCore/API/JSStringRef.h b/JavaScriptCore/API/JSStringRef.h index 8b17ee2..c58b958 100644 --- a/JavaScriptCore/API/JSStringRef.h +++ b/JavaScriptCore/API/JSStringRef.h @@ -37,7 +37,7 @@ extern "C" { #endif -#if !defined(WIN32) && !defined(_WIN32) +#if !defined(WIN32) && !defined(_WIN32) && !defined(__WINSCW__) /*! @typedef JSChar @abstract A Unicode character. diff --git a/JavaScriptCore/API/JSValueRef.cpp b/JavaScriptCore/API/JSValueRef.cpp index 2207181..31859d6 100644 --- a/JavaScriptCore/API/JSValueRef.cpp +++ b/JavaScriptCore/API/JSValueRef.cpp @@ -169,7 +169,7 @@ bool JSValueIsStrictEqual(JSContextRef ctx, JSValueRef a, JSValueRef b) JSValue jsA = toJS(exec, a); JSValue jsB = toJS(exec, b); - return JSValue::strictEqual(jsA, jsB); + return JSValue::strictEqual(exec, jsA, jsB); } bool JSValueIsInstanceOfConstructor(JSContextRef ctx, JSValueRef value, JSObjectRef constructor, JSValueRef* exception) @@ -307,7 +307,7 @@ void JSValueProtect(JSContextRef ctx, JSValueRef value) exec->globalData().heap.registerThread(); JSLock lock(exec); - JSValue jsValue = toJS(exec, value); + JSValue jsValue = toJSForGC(exec, value); gcProtect(jsValue); } @@ -317,6 +317,6 @@ void JSValueUnprotect(JSContextRef ctx, JSValueRef value) exec->globalData().heap.registerThread(); JSLock lock(exec); - JSValue jsValue = toJS(exec, value); + JSValue jsValue = toJSForGC(exec, value); gcUnprotect(jsValue); } diff --git a/JavaScriptCore/API/tests/testapi.c b/JavaScriptCore/API/tests/testapi.c index 1f413e1..e7aba0f 100644 --- a/JavaScriptCore/API/tests/testapi.c +++ b/JavaScriptCore/API/tests/testapi.c @@ -25,6 +25,7 @@ #include "JavaScriptCore.h" #include "JSBasePrivate.h" +#include "JSContextRefPrivate.h" #include <math.h> #define ASSERT_DISABLED 0 #include <wtf/Assertions.h> @@ -41,8 +42,8 @@ static double nan(const char*) #endif -static JSGlobalContextRef context = 0; -static int failed = 0; +static JSGlobalContextRef context; +static int failed; static void assertEqualsAsBoolean(JSValueRef value, bool expectedValue) { if (JSValueToBoolean(context, value) != expectedValue) { @@ -165,6 +166,10 @@ static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, if (JSStringIsEqualToUTF8CString(propertyName, "cantFind")) { return JSValueMakeUndefined(context); } + + if (JSStringIsEqualToUTF8CString(propertyName, "hasPropertyLie")) { + return 0; + } if (JSStringIsEqualToUTF8CString(propertyName, "throwOnGet")) { return JSEvaluateScript(context, JSStringCreateWithUTF8CString("throw 'an exception'"), object, JSStringCreateWithUTF8CString("test script"), 1, exception); @@ -175,7 +180,7 @@ static JSValueRef MyObject_getProperty(JSContextRef context, JSObjectRef object, return JSValueMakeNumber(context, 1); } - return NULL; + return JSValueMakeNull(context); } static bool MyObject_setProperty(JSContextRef context, JSObjectRef object, JSStringRef propertyName, JSValueRef value, JSValueRef* exception) @@ -298,7 +303,7 @@ static JSValueRef MyObject_convertToType(JSContextRef context, JSObjectRef objec } // string conversion -- forward to default object class - return NULL; + return JSValueMakeNull(context); } static JSStaticValue evilStaticValues[] = { @@ -373,7 +378,7 @@ static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObje funcName = JSStringCreateWithUTF8CString("toStringExplicit"); break; default: - return NULL; + return JSValueMakeNull(context); break; } @@ -381,7 +386,7 @@ static JSValueRef EvilExceptionObject_convertToType(JSContextRef context, JSObje JSStringRelease(funcName); JSObjectRef function = JSValueToObject(context, func, exception); if (!function) - return NULL; + return JSValueMakeNull(context); JSValueRef value = JSObjectCallAsFunction(context, function, object, 0, NULL, exception); if (!value) { JSStringRef errorString = JSStringCreateWithUTF8CString("convertToType failed"); @@ -618,14 +623,16 @@ static JSClassRef Derived_class(JSContextRef context) return jsClass; } -static JSValueRef print_callAsFunction(JSContextRef context, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) +static JSValueRef print_callAsFunction(JSContextRef ctx, JSObjectRef functionObject, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) { UNUSED_PARAM(functionObject); UNUSED_PARAM(thisObject); UNUSED_PARAM(exception); + + ASSERT(JSContextGetGlobalContext(ctx) == context); if (argumentCount > 0) { - JSStringRef string = JSValueToStringCopy(context, arguments[0], NULL); + JSStringRef string = JSValueToStringCopy(ctx, arguments[0], NULL); size_t sizeUTF8 = JSStringGetMaximumUTF8CStringSize(string); char* stringUTF8 = (char*)malloc(sizeUTF8); JSStringGetUTF8CString(string, stringUTF8, sizeUTF8); @@ -634,7 +641,7 @@ static JSValueRef print_callAsFunction(JSContextRef context, JSObjectRef functio JSStringRelease(string); } - return JSValueMakeUndefined(context); + return JSValueMakeUndefined(ctx); } static JSObjectRef myConstructor_callAsConstructor(JSContextRef context, JSObjectRef constructorObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* exception) @@ -734,6 +741,15 @@ static void testInitializeFinalize() ASSERT(JSObjectGetPrivate(o) == (void*)3); } +static JSValueRef jsNumberValue = NULL; + +static void makeGlobalNumberValue(JSContextRef context) { + JSValueRef v = JSValueMakeNumber(context, 420); + JSValueProtect(context, v); + jsNumberValue = v; + v = NULL; +} + int main(int argc, char* argv[]) { const char *scriptPath = "testapi.js"; @@ -760,6 +776,7 @@ int main(int argc, char* argv[]) JSGlobalContextRetain(context); JSGlobalContextRelease(context); + ASSERT(JSContextGetGlobalContext(context) == context); JSReportExtraMemoryCost(context, 0); JSReportExtraMemoryCost(context, 1); @@ -944,10 +961,12 @@ int main(int argc, char* argv[]) CFRelease(cfEmptyString); jsGlobalValue = JSObjectMake(context, NULL, NULL); + makeGlobalNumberValue(context); JSValueProtect(context, jsGlobalValue); JSGarbageCollect(context); ASSERT(JSValueIsObject(context, jsGlobalValue)); JSValueUnprotect(context, jsGlobalValue); + JSValueUnprotect(context, jsNumberValue); JSStringRef goodSyntax = JSStringCreateWithUTF8CString("x = 1;"); JSStringRef badSyntax = JSStringCreateWithUTF8CString("x := 1;"); diff --git a/JavaScriptCore/AllInOneFile.cpp b/JavaScriptCore/AllInOneFile.cpp index 7b67dbe..e69de29 100644 --- a/JavaScriptCore/AllInOneFile.cpp +++ b/JavaScriptCore/AllInOneFile.cpp @@ -1,106 +0,0 @@ -/* - * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public License - * along with this library; see the file COPYING.LIB. If not, write to - * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, - * Boston, MA 02110-1301, USA. - * - */ - -// 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 -#define JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE 1 -#include "config.h" - -// these headers are included here to avoid confusion between ::JSType and JSC::JSType -#include "JSCallbackConstructor.h" -#include "JSCallbackFunction.h" -#include "JSCallbackObject.h" - -#include "runtime/JSStaticScopeObject.cpp" -#include "runtime/JSFunction.cpp" -#include "runtime/Arguments.cpp" -#include "runtime/JSAPIValueWrapper.cpp" -#include "runtime/JSGlobalObjectFunctions.cpp" -#include "runtime/PrototypeFunction.cpp" -#include "runtime/GlobalEvalFunction.cpp" -#include "debugger/Debugger.cpp" -#include "runtime/JSArray.cpp" -#include "runtime/ArrayConstructor.cpp" -#include "runtime/ArrayPrototype.cpp" -#include "runtime/BooleanConstructor.cpp" -#include "runtime/BooleanObject.cpp" -#include "runtime/BooleanPrototype.cpp" -#include "runtime/Collector.cpp" -#include "runtime/CommonIdentifiers.cpp" -#include "runtime/DateConstructor.cpp" -#include "runtime/DateConversion.cpp" -#include "runtime/DatePrototype.cpp" -#include "runtime/DateInstance.cpp" -#include "wtf/dtoa.cpp" -#include "runtime/ErrorInstance.cpp" -#include "runtime/ErrorPrototype.cpp" -#include "runtime/ErrorConstructor.cpp" -#include "runtime/FunctionConstructor.cpp" -#include "runtime/FunctionPrototype.cpp" -#include "Grammar.cpp" -#include "runtime/Identifier.cpp" -#include "runtime/JSString.cpp" -#include "runtime/JSNumberCell.cpp" -#include "runtime/GetterSetter.cpp" -#include "runtime/InternalFunction.cpp" -#include "runtime/Completion.cpp" -#include "runtime/JSImmediate.cpp" -#include "runtime/JSLock.cpp" -#include "runtime/JSWrapperObject.cpp" -#include "parser/Lexer.cpp" -#include "runtime/ArgList.cpp" -#include "runtime/Lookup.cpp" -#include "runtime/MathObject.cpp" -#include "runtime/NativeErrorConstructor.cpp" -#include "runtime/NativeErrorPrototype.cpp" -#include "runtime/NumberConstructor.cpp" -#include "runtime/NumberObject.cpp" -#include "runtime/NumberPrototype.cpp" -#include "parser/Nodes.cpp" -#include "runtime/JSObject.cpp" -#include "runtime/Error.cpp" -#include "runtime/JSGlobalObject.cpp" -#include "runtime/ObjectConstructor.cpp" -#include "runtime/ObjectPrototype.cpp" -#include "runtime/Operations.cpp" -#include "parser/Parser.cpp" -#include "runtime/PropertySlot.cpp" -#include "runtime/PropertyNameArray.cpp" -#include "runtime/RegExp.cpp" -#include "runtime/RegExpConstructor.cpp" -#include "runtime/RegExpObject.cpp" -#include "runtime/RegExpPrototype.cpp" -#include "runtime/ScopeChain.cpp" -#include "runtime/StringConstructor.cpp" -#include "runtime/StringObject.cpp" -#include "runtime/StringPrototype.cpp" -#include "runtime/UString.cpp" -#include "runtime/JSValue.cpp" -#include "runtime/CallData.cpp" -#include "runtime/ConstructData.cpp" -#include "runtime/JSCell.cpp" -#include "runtime/JSVariableObject.cpp" -#include "wtf/FastMalloc.cpp" -#include "wtf/TCSystemAlloc.cpp" -#include "bytecompiler/BytecodeGenerator.cpp" -#include "interpreter/RegisterFile.cpp" diff --git a/JavaScriptCore/Android.mk b/JavaScriptCore/Android.mk index 774ae4c..425d69c 100644 --- a/JavaScriptCore/Android.mk +++ b/JavaScriptCore/Android.mk @@ -1,58 +1,33 @@ ## +## Copyright 2009, The Android Open Source Project ## -## Copyright 2007, The Android Open Source Project +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. ## -## Licensed under the Apache License, Version 2.0 (the "License"); -## you may not use this file except in compliance with the License. -## You may obtain a copy of the License at +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. ## -## http://www.apache.org/licenses/LICENSE-2.0 -## -## Unless required by applicable law or agreed to in writing, software -## distributed under the License is distributed on an "AS IS" BASIS, -## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -## See the License for the specific language governing permissions and -## limitations under the License. -## - -#LOCAL_CFLAGS += -E -v - -# This comment block is read by tools/webkitsync/diff.cpp -# Don't remove it or move it. -# -# The following files are intentionally not included -# LOCAL_SRC_FILES_EXCLUDED := \ -# AllInOneFile.cpp \ -# jsc.cpp \ -# parser/Grammar.y \ -# pcre/ucptable.cpp \ -# wtf/GOwnPtr.cpp \ -# wtf/*Gtk.cpp \ -# wtf/*Qt.cpp \ -# wtf/*Win.cpp \ - -# This comment block is read by tools/webkitsync/diff.cpp -# Don't remove it or move it. -# -# The following directory wildcard matches are intentionally not included -# If an entry starts with '/', any subdirectory may match -# If an entry starts with '^', the first directory must match -# LOCAL_DIR_WILDCARD_EXCLUDED := \ -# ^API/* \ -# /chromium/* \ -# /gtk/* \ -# ^jit/* \ -# /mac/* \ -# /qt/* \ -# /win/* \ -# /wx/* \ LOCAL_SRC_FILES := \ - API/JSValueRef.cpp \ + API/JSValueRef.cpp \ API/JSCallbackObject.cpp \ API/OpaqueJSString.cpp \ \ - assembler/ARMAssembler.cpp \ bytecode/CodeBlock.cpp \ bytecode/JumpTable.cpp \ bytecode/Opcode.cpp \ @@ -60,6 +35,7 @@ LOCAL_SRC_FILES := \ bytecode/StructureStubInfo.cpp \ \ bytecompiler/BytecodeGenerator.cpp \ + bytecompiler/NodesCodegen.cpp \ \ debugger/Debugger.cpp \ debugger/DebuggerActivation.cpp \ @@ -108,6 +84,7 @@ LOCAL_SRC_FILES := \ runtime/ErrorInstance.cpp \ runtime/ErrorPrototype.cpp \ runtime/ExceptionHelpers.cpp \ + runtime/Executable.cpp \ runtime/FunctionConstructor.cpp \ runtime/FunctionPrototype.cpp \ runtime/GetterSetter.cpp \ @@ -149,6 +126,7 @@ LOCAL_SRC_FILES := \ runtime/ObjectConstructor.cpp \ runtime/ObjectPrototype.cpp \ runtime/Operations.cpp \ + runtime/PropertyDescriptor.cpp \ runtime/PropertyNameArray.cpp \ runtime/PropertySlot.cpp \ runtime/PrototypeFunction.cpp \ diff --git a/JavaScriptCore/Android.v8.wtf.mk b/JavaScriptCore/Android.v8.wtf.mk index 6207319..53a50d9 100644 --- a/JavaScriptCore/Android.v8.wtf.mk +++ b/JavaScriptCore/Android.v8.wtf.mk @@ -1,3 +1,28 @@ +## +## Copyright 2009, The Android Open Source Project +## +## Redistribution and use in source and binary forms, with or without +## modification, are permitted provided that the following conditions +## are met: +## * Redistributions of source code must retain the above copyright +## notice, this list of conditions and the following disclaimer. +## * Redistributions in binary form must reproduce the above copyright +## notice, this list of conditions and the following disclaimer in the +## documentation and/or other materials provided with the distribution. +## +## THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +## EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +## IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +## PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +## CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +## EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +## PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +## PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +## OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +## (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +## OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +## + # wtf source files LOCAL_SRC_FILES := \ diff --git a/JavaScriptCore/ChangeLog b/JavaScriptCore/ChangeLog index 1afea5f..829cc98 100644 --- a/JavaScriptCore/ChangeLog +++ b/JavaScriptCore/ChangeLog @@ -1,3 +1,8848 @@ +2009-12-10 Adam Barth <abarth@webkit.org> + + No review, rolling out r51975. + http://trac.webkit.org/changeset/51975 + + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * runtime/JSString.h: + (JSC::JSString::JSString): + (JSC::JSString::appendStringInConstruct): + * runtime/Operations.cpp: + (JSC::jsAddSlowCase): + * runtime/Operations.h: + (JSC::jsString): + (JSC::jsAdd): + +2009-12-10 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Incorrect caching of prototype lookup with dictionary base + https://bugs.webkit.org/show_bug.cgi?id=32402 + + Make sure we don't add cached prototype lookup to the proto_list + lookup chain if the top level object is a dictionary. + + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCacheGetByID): + +2009-12-10 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=32400 + Switch remaining cases of string addition to use ropes. + + ~1% progression on Sunspidey. + + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * runtime/JSString.h: + (JSC::JSString::JSString): + (JSC::JSString::appendStringInConstruct): + * runtime/Operations.cpp: + (JSC::jsAddSlowCase): + * runtime/Operations.h: + (JSC::jsString): + (JSC::jsAdd): + +2009-12-10 Kent Hansen <kent.hansen@nokia.com> + + Reviewed by Geoffrey Garen. + + Remove JSObject::getPropertyAttributes() and all usage of it. + https://bugs.webkit.org/show_bug.cgi?id=31933 + + getOwnPropertyDescriptor() should be used instead. + + * JavaScriptCore.exp: + * JavaScriptCore.order: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * debugger/DebuggerActivation.cpp: + (JSC::DebuggerActivation::getOwnPropertyDescriptor): + * debugger/DebuggerActivation.h: + * runtime/JSObject.cpp: + (JSC::JSObject::propertyIsEnumerable): + * runtime/JSObject.h: + * runtime/JSVariableObject.cpp: + * runtime/JSVariableObject.h: + +2009-12-10 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt & Mark Rowe. + + https://bugs.webkit.org/show_bug.cgi?id=32367 + Add support for short Ropes (up to 3 entries) inline within JSString. + (rather than externally allocating an object to hold the rope). + Switch jsAdd of (JSString* + JSString*) to now make use of Ropes. + + ~1% progression on Sunspidey. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * runtime/JSString.cpp: + (JSC::JSString::resolveRope): + (JSC::JSString::toBoolean): + (JSC::JSString::getStringPropertyDescriptor): + * runtime/JSString.h: + (JSC::JSString::Rope::Fiber::deref): + (JSC::JSString::Rope::Fiber::ref): + (JSC::JSString::Rope::Fiber::refAndGetLength): + (JSC::JSString::Rope::append): + (JSC::JSString::JSString): + (JSC::JSString::~JSString): + (JSC::JSString::value): + (JSC::JSString::tryGetValue): + (JSC::JSString::length): + (JSC::JSString::canGetIndex): + (JSC::JSString::appendStringInConstruct): + (JSC::JSString::appendValueInConstructAndIncrementLength): + (JSC::JSString::isRope): + (JSC::JSString::string): + (JSC::JSString::ropeLength): + (JSC::JSString::getStringPropertySlot): + * runtime/Operations.h: + (JSC::jsString): + (JSC::jsAdd): + (JSC::resolveBase): + +2009-12-09 Anders Carlsson <andersca@apple.com> + + Reviewed by Geoffrey Garen. + + Fix three more things found by compiling with clang++. + + * runtime/Structure.h: + (JSC::StructureTransitionTable::reifySingleTransition): + Add the 'std' qualifier to the call to make_pair. + + * wtf/DateMath.cpp: + (WTF::initializeDates): + Incrementing a bool is deprecated according to the C++ specification. + + * wtf/PtrAndFlags.h: + (WTF::PtrAndFlags::PtrAndFlags): + Name lookup should not be done in dependent bases, so explicitly qualify the call to set. + +2009-12-09 Maciej Stachowiak <mjs@apple.com> + + Reviewed by Oliver Hunt. + + Google reader gets stuck in the "Loading..." state and does not complete + https://bugs.webkit.org/show_bug.cgi?id=32256 + <rdar://problem/7456388> + + * jit/JITArithmetic.cpp: + (JSC::JIT::emitSlow_op_jless): Fix some backward branches. + +2009-12-09 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=32228 + Make destruction of ropes non-recursive to prevent stack exhaustion. + Also, pass a UString& into initializeFiber rather than a Ustring::Rep*, + since the Rep is not being ref counted this could result in usage of a + Rep with refcount zero (where the Rep comes from a temporary UString + returned from a function). + + * runtime/JSString.cpp: + (JSC::JSString::Rope::destructNonRecursive): + (JSC::JSString::Rope::~Rope): + * runtime/JSString.h: + (JSC::JSString::Rope::initializeFiber): + * runtime/Operations.h: + (JSC::concatenateStrings): + +2009-12-09 Zoltan Herczeg <zherczeg@inf.u-szeged.hu> + + Reviewed by Eric Seidel. + + https://bugs.webkit.org/show_bug.cgi?id=31930 + + Update to r51457. ASSERTs changed to COMPILE_ASSERTs. + The speedup is 25%. + + * runtime/JSGlobalData.cpp: + (JSC::VPtrSet::VPtrSet): + +2009-12-09 Steve Block <steveblock@google.com> + + Reviewed by Adam Barth. + + Updates Android Makefiles with latest additions. + https://bugs.webkit.org/show_bug.cgi?id=32278 + + * Android.mk: Modified. + * Android.v8.wtf.mk: Modified. + +2009-12-09 Sam Weinig <sam@webkit.org> + + Reviewed by Gavin Barraclough. + + Fix a bug found while trying to compile JavaScriptCore with clang++. + + * yarr/RegexPattern.h: + (JSC::Yarr::PatternTerm::PatternTerm): Don't self assign here. Use false instead. + +2009-12-09 Anders Carlsson <andersca@apple.com> + + Reviewed by Sam Weinig. + + Attempt to fix the Windows build. + + * wtf/FastMalloc.h: + +2009-12-09 Anders Carlsson <andersca@apple.com> + + Reviewed by Sam Weinig. + + Fix some things found while trying to compile JavaScriptCore with clang++. + + * wtf/FastMalloc.h: + Add correct exception specifications for the allocation/deallocation operators. + + * wtf/Vector.h: + * wtf/VectorTraits.h: + Fix a bunch of struct/class mismatches. + +2009-12-08 Maciej Stachowiak <mjs@apple.com> + + Reviewed by Darin Adler. + + move code generation portions of Nodes.cpp to bytecompiler directory + https://bugs.webkit.org/show_bug.cgi?id=32284 + + * bytecompiler/NodesCodegen.cpp: Copied from parser/Nodes.cpp. Removed parts that + are not about codegen. + * parser/Nodes.cpp: Removed everything that is about codegen. + + Update build systems: + + * Android.mk: + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.pri: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * JavaScriptCoreSources.bkl: + +2009-12-08 Kevin Watters <kevinwatters@gmail.com> + + Reviewed by Kevin Ollivier. + + [wx] Mac plugins support. + + https://bugs.webkit.org/show_bug.cgi?id=32236 + + * wtf/Platform.h: + +2009-12-08 Dmitry Titov <dimich@chromium.org> + + Rubber-stamped by David Levin. + + Revert and reopen "Add asserts to RefCounted to make sure ref/deref happens on the right thread." + It may have caused massive increase of reported leaks on the bots. + https://bugs.webkit.org/show_bug.cgi?id=31639 + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/WTF/WTF.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/Structure.cpp: + (JSC::Structure::Structure): + * wtf/RefCounted.h: + (WTF::RefCountedBase::ref): + (WTF::RefCountedBase::hasOneRef): + (WTF::RefCountedBase::refCount): + (WTF::RefCountedBase::derefBase): + * wtf/ThreadVerifier.h: Removed. + +2009-12-08 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk> + + Reviewed by Darin Adler. + + Make WebKit build correctly on FreeBSD, IA64, and Alpha. + Based on work by Petr Salinger <Petr.Salinger@seznam.cz>, + and Colin Watson <cjwatson@ubuntu.com>. + + * wtf/Platform.h: + +2009-12-08 Dmitry Titov <dimich@chromium.org> + + Reviewed by Darin Adler. + + Add asserts to RefCounted to make sure ref/deref happens on the right thread. + https://bugs.webkit.org/show_bug.cgi?id=31639 + + * runtime/Structure.cpp: + (JSC::Structure::Structure): Disable thread verification on this class since it uses addressOfCount(). + * wtf/RefCounted.h: + (WTF::RefCountedBase::ref): Add ASSERT. + (WTF::RefCountedBase::hasOneRef): Ditto. + (WTF::RefCountedBase::refCount): Ditto. + (WTF::RefCountedBase::derefBase): Ditto. + (WTF::RefCountedBase::disableThreadVerification): delegate to ThreadVerifier method. + * wtf/ThreadVerifier.h: Added. + (WTF::ThreadVerifier::ThreadVerifier): New Debug-only class to verify that ref/deref of RefCounted is done on the same thread. + (WTF::ThreadVerifier::activate): Activates checks. Called when ref count becomes above 2. + (WTF::ThreadVerifier::deactivate): Deactivates checks. Called when ref count drops below 2. + (WTF::ThreadVerifier::disableThreadVerification): used on objects that should not be checked (StringImpl etc) + (WTF::ThreadVerifier::verifyThread): + * GNUmakefile.am: Add ThreadVerifier.h to the build file. + * JavaScriptCore.gypi: Ditto. + * JavaScriptCore.vcproj/WTF/WTF.vcproj: Ditto. + * JavaScriptCore.xcodeproj/project.pbxproj: Ditto. + +2009-12-08 Steve Block <steveblock@google.com> + + Reviewed by Adam Barth. + + [Android] Adds Makefiles for Android port. + https://bugs.webkit.org/show_bug.cgi?id=31325 + + * Android.mk: Added. + * Android.v8.wtf.mk: Added. + +2009-12-07 Dmitry Titov <dimich@chromium.org> + + Rubber-stamped by Darin Adler. + + Remove ENABLE_SHARED_SCRIPT flags + https://bugs.webkit.org/show_bug.cgi?id=32245 + This patch was obtained by "git revert" command and then un-reverting of ChangeLog files. + + * Configurations/FeatureDefines.xcconfig: + * wtf/Platform.h: + +2009-12-07 Gavin Barraclough <barraclough@apple.com> + + Reviewed by NOBODY (Windows build fixage part I). + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2009-12-05 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=32184 + Handle out-of-memory conditions with JSC Ropes with a JS exception, rather than crashing. + Switch from using fastMalloc to tryFastMalloc, pass an ExecState to record the exception on. + + * API/JSCallbackObjectFunctions.h: + (JSC::::toString): + * API/JSValueRef.cpp: + (JSValueIsStrictEqual): + * JavaScriptCore.exp: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitEqualityOp): + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::functionName): + (JSC::DebuggerCallFrame::calculatedFunctionName): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::callEval): + (JSC::Interpreter::privateExecute): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * profiler/ProfileGenerator.cpp: + (JSC::ProfileGenerator::addParentForConsoleStart): + * profiler/Profiler.cpp: + (JSC::Profiler::willExecute): + (JSC::Profiler::didExecute): + (JSC::Profiler::createCallIdentifier): + (JSC::createCallIdentifierFromFunctionImp): + * profiler/Profiler.h: + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncIndexOf): + (JSC::arrayProtoFuncLastIndexOf): + * runtime/DateConstructor.cpp: + (JSC::constructDate): + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncToString): + * runtime/InternalFunction.cpp: + (JSC::InternalFunction::name): + (JSC::InternalFunction::displayName): + (JSC::InternalFunction::calculatedDisplayName): + * runtime/InternalFunction.h: + * runtime/JSCell.cpp: + (JSC::JSCell::getString): + * runtime/JSCell.h: + (JSC::JSValue::getString): + * runtime/JSONObject.cpp: + (JSC::gap): + (JSC::Stringifier::Stringifier): + (JSC::Stringifier::appendStringifiedValue): + * runtime/JSObject.cpp: + (JSC::JSObject::putDirectFunction): + (JSC::JSObject::putDirectFunctionWithoutTransition): + (JSC::JSObject::defineOwnProperty): + * runtime/JSObject.h: + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::get): + * runtime/JSString.cpp: + (JSC::JSString::Rope::~Rope): + (JSC::JSString::resolveRope): + (JSC::JSString::getPrimitiveNumber): + (JSC::JSString::toNumber): + (JSC::JSString::toString): + (JSC::JSString::toThisString): + (JSC::JSString::getStringPropertyDescriptor): + * runtime/JSString.h: + (JSC::JSString::Rope::createOrNull): + (JSC::JSString::Rope::operator new): + (JSC::JSString::value): + (JSC::JSString::tryGetValue): + (JSC::JSString::getIndex): + (JSC::JSString::getStringPropertySlot): + (JSC::JSValue::toString): + * runtime/JSValue.h: + * runtime/NativeErrorConstructor.cpp: + (JSC::NativeErrorConstructor::NativeErrorConstructor): + * runtime/Operations.cpp: + (JSC::JSValue::strictEqualSlowCase): + * runtime/Operations.h: + (JSC::JSValue::equalSlowCaseInline): + (JSC::JSValue::strictEqualSlowCaseInline): + (JSC::JSValue::strictEqual): + (JSC::jsLess): + (JSC::jsLessEq): + (JSC::jsAdd): + (JSC::concatenateStrings): + * runtime/PropertyDescriptor.cpp: + (JSC::PropertyDescriptor::equalTo): + * runtime/PropertyDescriptor.h: + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncReplace): + (JSC::stringProtoFuncToLowerCase): + (JSC::stringProtoFuncToUpperCase): + +2009-12-07 Nikolas Zimmermann <nzimmermann@rim.com> + + Reviewed by Holger Freyther. + + Turn on (SVG) Filters support, by default. + https://bugs.webkit.org/show_bug.cgi?id=32224 + + * Configurations/FeatureDefines.xcconfig: Enable FILTERS build flag. + +2009-12-07 Steve Falkenburg <sfalken@apple.com> + + Build fix. Be flexible about which version of ICU is used on Windows. + + * JavaScriptCore.vcproj/jsc/jscCommon.vsprops: Add optional xcopy commands to copy ICU 4.2. + +2009-12-07 Maciej Stachowiak <mjs@apple.com> + + Reviewed by Oliver Hunt. + + op_loop_if_less JIT codegen is broken for 64-bit + https://bugs.webkit.org/show_bug.cgi?id=32221 + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_loop_if_false): Fix codegen in this version - test was backwards. + +2009-12-07 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Object.create fails if properties on the descriptor are getters + https://bugs.webkit.org/show_bug.cgi?id=32219 + + Correctly initialise the PropertySlots with the descriptor object. + + * runtime/ObjectConstructor.cpp: + (JSC::toPropertyDescriptor): + +2009-12-06 Maciej Stachowiak <mjs@apple.com> + + Not reviewed, build fix. + + Actually tested 64-bit *and* 32-bit build this time. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_loop_if_false): + +2009-12-06 Maciej Stachowiak <mjs@apple.com> + + Not reviewed, build fix. + + Really really fix 64-bit build for prior patch (actually tested this time). + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_loop_if_false): + (JSC::JIT::emitSlow_op_loop_if_false): + +2009-12-06 Maciej Stachowiak <mjs@apple.com> + + Not reviewed, build fix. + + Really fix 64-bit build for prior patch. + + * jit/JITArithmetic.cpp: + (JSC::JIT::emitSlow_op_jless): + +2009-12-06 Maciej Stachowiak <mjs@apple.com> + + Not reviewed, build fix. + + Fix 64-bit build for prior patch. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emitSlow_op_loop_if_less): + +2009-12-05 Maciej Stachowiak <mjs@apple.com> + + Reviewed by Oliver Hunt. + + conway benchmark spends half it's time in op_less (jump fusion fails) + https://bugs.webkit.org/show_bug.cgi?id=32190 + + <1% speedup on SunSpider and V8 + 2x speedup on "conway" benchmark + + Two optimizations: + 1) Improve codegen for logical operators &&, || and ! in a condition context + + When generating code for combinations of &&, || and !, in a + condition context (i.e. in an if statement or loop condition), we + used to produce a value, and then separately jump based on its + truthiness. Now we pass the false and true targets in, and let the + logical operators generate jumps directly. This helps in four + ways: + + a) Individual clauses of a short-circuit logical operator can now + jump directly to the then or else clause of an if statement (or to + the top or exit of a loop) instead of jumping to a jump. + + b) It used to be that jump fusion with the condition of the first + clause of a logical operator was inhibited, because the register + was ref'd to be used later, in the actual condition jump; this no + longer happens since a jump straight to the final target is + generated directly. + + c) It used to be that jump fusion with the condition of the second + clause of a logical operator was inhibited, because there was a + jump target right after the second clause and before the actual + condition jump. But now it's no longer necessary for the first + clause to jump there so jump fusion is not blocked. + + d) We avoid generating excess mov statements in some cases. + + As a concrete example this source: + + if (!((x < q && y < q) || (t < q && z < q))) { + // ... + } + + Used to generate this bytecode: + + [ 34] less r1, r-15, r-19 + [ 38] jfalse r1, 7(->45) + [ 41] less r1, r-16, r-19 + [ 45] jtrue r1, 14(->59) + [ 48] less r1, r-17, r-19 + [ 52] jfalse r1, 7(->59) + [ 55] less r1, r-18, r-19 + [ 59] jtrue r1, 17(->76) + + And now generates this bytecode (also taking advantage of the second optimization below): + + [ 34] jnless r-15, r-19, 8(->42) + [ 38] jless r-16, r-19, 26(->64) + [ 42] jnless r-17, r-19, 8(->50) + [ 46] jless r-18, r-19, 18(->64) + + Note the jump fusion and the fact that there's less jump + indirection - three of the four jumps go straight to the target + clause instead of indirecting through another jump. + + 2) Implement jless opcode to take advantage of the above, since we'll now often generate + a less followed by a jtrue where fusion is not forbidden. + + * parser/Nodes.h: + (JSC::ExpressionNode::hasConditionContextCodegen): Helper function to determine + whether a node supports special conditional codegen. Return false as this is the default. + (JSC::ExpressionNode::emitBytecodeInConditionContext): Assert not reached - only really + defined for nodes that do have conditional codegen. + (JSC::UnaryOpNode::expr): Add const version. + (JSC::LogicalNotNode::hasConditionContextCodegen): Returne true only if subexpression + supports it. + (JSC::LogicalOpNode::hasConditionContextCodegen): Return true. + * parser/Nodes.cpp: + (JSC::LogicalNotNode::emitBytecodeInConditionContext): Implemented - just swap + the true and false targets for the child node. + (JSC::LogicalOpNode::emitBytecodeInConditionContext): Implemented - handle jumps + directly, improving codegen quality. Also handles further nested conditional codegen. + (JSC::ConditionalNode::emitBytecode): Use condition context codegen when available. + (JSC::IfNode::emitBytecode): ditto + (JSC::IfElseNode::emitBytecode): ditto + (JSC::DoWhileNode::emitBytecode): ditto + (JSC::WhileNode::emitBytecode): ditto + (JSC::ForNode::emitBytecode): ditto + + * bytecode/Opcode.h: + - Added loop_if_false opcode - needed now that falsey jumps can be backwards. + - Added jless opcode to take advantage of new fusion opportunities. + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): Handle above. + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitJumpIfTrue): Add peephole for less + jtrue ==> jless. + (JSC::BytecodeGenerator::emitJumpIfFalse): Add handling of backwrds falsey jumps. + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::emitNodeInConditionContext): Wrapper to handle tracking of + overly deep expressions etc. + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): Implement the two new opcodes (loop_if_false, jless). + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): Implement JIT support for the two new opcodes. + (JSC::JIT::privateCompileSlowCases): ditto + * jit/JIT.h: + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_jless): + (JSC::JIT::emitSlow_op_jless): ditto + (JSC::JIT::emitBinaryDoubleOp): ditto + * jit/JITOpcodes.cpp: + (JSC::JIT::emitSlow_op_loop_if_less): ditto + (JSC::JIT::emit_op_loop_if_false): ditto + (JSC::JIT::emitSlow_op_loop_if_false): ditto + * jit/JITStubs.cpp: + * jit/JITStubs.h: + (JSC::): + +2009-12-04 Kent Hansen <kent.hansen@nokia.com> + + Reviewed by Darin Adler. + + JavaScript delete operator should return false for string properties + https://bugs.webkit.org/show_bug.cgi?id=32012 + + * runtime/StringObject.cpp: + (JSC::StringObject::deleteProperty): + +2009-12-03 Drew Wilson <atwilson@chromium.org> + + Rolled back r51633 because it causes a perf regression in Chromium. + + * wtf/Platform.h: + +2009-12-03 Gavin Barraclough <barraclough@apple.com> + + Try and fix the Windows build. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Export a symbol that should be exported. + +2009-12-03 Mark Rowe <mrowe@apple.com> + + Try and fix the Mac build. + + * JavaScriptCore.exp: Export a symbol that should be exported. + +2009-12-03 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + REGRESSION(4.0.3-48777): Crash in JSC::ExecState::propertyNames() (Debug-only?) + https://bugs.webkit.org/show_bug.cgi?id=32133 + + Work around odd GCC-ism and correct the scopechain for use by + calls made while a cachedcall is active on the callstack. + + * interpreter/CachedCall.h: + (JSC::CachedCall::newCallFrame): + * runtime/JSArray.cpp: + (JSC::AVLTreeAbstractorForArrayCompare::compare_key_key): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncReplace): + +2009-12-03 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver "Brraaaaiiiinnnnnzzzzzzzz" Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=32136 + Add a rope representation to JSString. Presently JSString always holds its data in UString form. + Instead, allow the result of a string concatenation to be represented in a tree form - with a + variable sized, reference-counted rope node retaining a set of UString::Reps (or other rope nopes). + + Strings must still currently be resolved down to a flat UString representation before being used, + but by holding the string in a rope representation during construction we can avoid copying data + until we know the final size of the string. + + ~2% progression on SunSpider (~25% on date-format-xparb, ~20% on string-validate-input). + + * JavaScriptCore.exp: + + - Update exports. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + + - Make use of new JSString::length() method to avoid prematurely resolving ropes. + + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + + - Switch the string length trampoline to read the length directly from JSString::m_length, + rather than from the JSString's UString::Rep's 'len' property. + + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + + - Modify op_add such that addition of two strings, where either or both strings are already + in rope representation, produces a rope as a result. + + * runtime/JSString.cpp: + (JSC::JSString::Rope::~Rope): + (JSC::copyChars): + (JSC::JSString::resolveRope): + (JSC::JSString::getPrimitiveNumber): + (JSC::JSString::toBoolean): + (JSC::JSString::toNumber): + (JSC::JSString::toString): + (JSC::JSString::toThisString): + (JSC::JSString::getStringPropertyDescriptor): + * runtime/JSString.h: + (JSC::JSString::Rope::Fiber::Fiber): + (JSC::JSString::Rope::Fiber::destroy): + (JSC::JSString::Rope::Fiber::isRope): + (JSC::JSString::Rope::Fiber::rope): + (JSC::JSString::Rope::Fiber::string): + (JSC::JSString::Rope::create): + (JSC::JSString::Rope::initializeFiber): + (JSC::JSString::Rope::ropeLength): + (JSC::JSString::Rope::stringLength): + (JSC::JSString::Rope::fibers): + (JSC::JSString::Rope::Rope): + (JSC::JSString::Rope::operator new): + (JSC::JSString::JSString): + (JSC::JSString::value): + (JSC::JSString::length): + (JSC::JSString::isRope): + (JSC::JSString::rope): + (JSC::JSString::string): + (JSC::JSString::canGetIndex): + (JSC::jsSingleCharacterSubstring): + (JSC::JSString::getIndex): + (JSC::jsSubstring): + (JSC::JSString::getStringPropertySlot): + + - Add rope form. + + * runtime/Operations.h: + (JSC::jsAdd): + (JSC::concatenateStrings): + + - Update string concatenation, and addition of ropes, to produce ropes. + + * runtime/StringObject.cpp: + (JSC::StringObject::getOwnPropertyNames): + + - Make use of new JSString::length() method to avoid prematurely resolving ropes. + +2009-11-23 Jeremy Moskovich <jeremy@chromium.org> + + Reviewed by Eric Seidel. + + Switch Chrome/Mac to use Core Text APIs rather than ATSUI APIs. + https://bugs.webkit.org/show_bug.cgi?id=31802 + + No test since this is already covered by existing pixel tests. + + * wtf/Platform.h: #define USE_CORE_TEXT for Chrome/Mac. + +2009-12-02 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Add files missed in prior patch. + + * runtime/JSZombie.cpp: + (JSC::): + (JSC::JSZombie::leakedZombieStructure): + * runtime/JSZombie.h: Added. + (JSC::JSZombie::JSZombie): + (JSC::JSZombie::isZombie): + (JSC::JSZombie::classInfo): + (JSC::JSZombie::isGetterSetter): + (JSC::JSZombie::isAPIValueWrapper): + (JSC::JSZombie::isPropertyNameIterator): + (JSC::JSZombie::getCallData): + (JSC::JSZombie::getConstructData): + (JSC::JSZombie::getUInt32): + (JSC::JSZombie::toPrimitive): + (JSC::JSZombie::getPrimitiveNumber): + (JSC::JSZombie::toBoolean): + (JSC::JSZombie::toNumber): + (JSC::JSZombie::toString): + (JSC::JSZombie::toObject): + (JSC::JSZombie::markChildren): + (JSC::JSZombie::put): + (JSC::JSZombie::deleteProperty): + (JSC::JSZombie::toThisObject): + (JSC::JSZombie::toThisString): + (JSC::JSZombie::toThisJSString): + (JSC::JSZombie::getJSNumber): + (JSC::JSZombie::getOwnPropertySlot): + +2009-12-02 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Add zombies to JSC + https://bugs.webkit.org/show_bug.cgi?id=32103 + + Add a compile time flag to make the JSC collector replace "unreachable" + objects with zombie objects. The zombie object is a JSCell subclass that + ASSERTs on any attempt to use the JSCell methods. In addition there are + a number of additional assertions in bottleneck code to catch zombie usage + as quickly as possible. + + Grrr. Argh. Brains. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * interpreter/Register.h: + (JSC::Register::Register): + * runtime/ArgList.h: + (JSC::MarkedArgumentBuffer::append): + (JSC::ArgList::ArgList): + * runtime/Collector.cpp: + (JSC::Heap::destroy): + (JSC::Heap::sweep): + * runtime/Collector.h: + * runtime/JSCell.h: + (JSC::JSCell::isZombie): + (JSC::JSValue::isZombie): + * runtime/JSValue.h: + (JSC::JSValue::decode): + (JSC::JSValue::JSValue): + * wtf/Platform.h: + +2009-12-01 Jens Alfke <snej@chromium.org> + + Reviewed by Darin Adler. + + Added variants of find/contains/add that allow a foreign key type to be used. + This will allow AtomicString-keyed maps to be queried by C string without + having to create a temporary AtomicString (see HTTPHeaderMap.) + The code for this is adapted from the equivalent in HashSet.h. + + * wtf/HashMap.h: + (WTF::HashMap::find): + (WTF::HashMap::contains): + (WTF::HashMap::add): + * wtf/HashSet.h: Changed "method" to "function member" in a comment. + +2009-12-01 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk> + + Revert 51551 because it broke GTK+. + + * wtf/Platform.h: + +2009-11-30 Gavin Barraclough <barraclough@apple.com> + + Windows Build fix. Reviewed by NOBODY. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2009-11-24 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Geoff Garen. + + Bug 31859 - Make world selection for JSC IsolatedWorlds automagical. + + WebCore presently has to explicitly specify the world before entering into JSC, + which is a little fragile (particularly since property access via a + getter/setter might invoke execution). Instead derive the current world from + the lexical global object. + + Remove the temporary duct tape of willExecute/didExecute virtual hooks on the JSGlobalData::ClientData - these are no longer necessary. + + * API/JSBase.cpp: + (JSEvaluateScript): + * API/JSObjectRef.cpp: + (JSObjectCallAsFunction): + * JavaScriptCore.exp: + * runtime/JSGlobalData.cpp: + * runtime/JSGlobalData.h: + +2009-11-30 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Remove obsolete PLATFORM(KDE) code + https://bugs.webkit.org/show_bug.cgi?id=31958 + + KDE is now using unpatched QtWebKit. + + * parser/Lexer.cpp: Remove obsolete KDE_USE_FINAL guard + * wtf/Platform.h: Remove PLATFORM(KDE) definition and code + section that is guarded with it. + +2009-11-30 Jan-Arve Sæther <jan-arve.saether@nokia.com> + + Reviewed by Simon Hausmann. + + [Qt] Fix compilation with win32-icc + + The Intel compiler does not support the __has_trivial_constructor type + trait. The Intel Compiler can report itself as _MSC_VER >= 1400. The + reason for that is that the Intel Compiler depends on the Microsoft + Platform SDK, and in order to try to be "fully" MS compatible it will + "pretend" to be the same MS compiler as was shipped with the MS PSDK. + (Thus, compiling with win32-icc with VC8 SDK will make the source code + "think" the compiler at hand supports this type trait). + + * wtf/TypeTraits.h: + +2009-11-29 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Eric Seidel. + + [Qt] Mac build has JIT disabled + https://bugs.webkit.org/show_bug.cgi?id=31828 + + * wtf/Platform.h: Enable JIT for Qt Mac builds + +2009-11-28 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Eric Seidel. + + Apply workaround for the limitation of VirtualFree with MEM_RELEASE to all ports running on Windows + https://bugs.webkit.org/show_bug.cgi?id=31943 + + * runtime/MarkStack.h: + (JSC::MarkStack::MarkStackArray::shrinkAllocation): + +2009-11-28 Zoltan Herczeg <zherczeg@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + https://bugs.webkit.org/show_bug.cgi?id=31930 + + Seems a typo. We don't need ~270k memory to determine the vptrs. + + * runtime/JSGlobalData.cpp: + (JSC::VPtrSet::VPtrSet): + +2009-11-27 Shinichiro Hamaji <hamaji@chromium.org> + + Unreviewed. + + Move GOwnPtr* from wtf to wtf/gtk + https://bugs.webkit.org/show_bug.cgi?id=31793 + + Build fix for chromium after r51423. + Exclude gtk directory from chromium build. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + +2009-11-25 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Incorrect behaviour of jneq_null in the interpreter + https://bugs.webkit.org/show_bug.cgi?id=31901 + + Correct the logic of jneq_null. This is already covered by existing tests. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + +2009-11-26 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Oliver Hunt. + + Move GOwnPtr* from wtf to wtf/gtk + https://bugs.webkit.org/show_bug.cgi?id=31793 + + * GNUmakefile.am: Change the path for GOwnPtr.*. + * JavaScriptCore.gyp/JavaScriptCore.gyp: Remove + GOwnPtr.cpp from the exclude list. + * JavaScriptCore.gypi: Change the path for GOwnPtr.*. + * wscript: Remove GOwnPtr.cpp from the exclude list. + * wtf/GOwnPtr.cpp: Removed. + * wtf/GOwnPtr.h: Removed. + * wtf/Threading.h: Change the path for GOwnPtr.h. + * wtf/gtk/GOwnPtr.cpp: Copied from JavaScriptCore/wtf/GOwnPtr.cpp. + * wtf/gtk/GOwnPtr.h: Copied from JavaScriptCore/wtf/GOwnPtr.h. + * wtf/unicode/glib/UnicodeGLib.h: Change the path for GOwnPtr.h. + +2009-11-24 Dmitry Titov <dimich@chromium.org> + + Reviewed by Eric Seidel. + + Add ENABLE_SHARED_SCRIPT feature define and flag for build-webkit + https://bugs.webkit.org/show_bug.cgi?id=31444 + + * Configurations/FeatureDefines.xcconfig: + * wtf/Platform.h: + +2009-11-24 Chris Marrin <cmarrin@apple.com> + + Reviewed by Simon Fraser. + + Add ability to enable ACCELERATED_COMPOSITING on Windows (currently disabled) + https://bugs.webkit.org/show_bug.cgi?id=27314 + + * wtf/Platform.h: + +2009-11-24 Jason Smith <dark.panda@gmail.com> + + Reviewed by Alexey Proskuryakov. + + RegExp#exec's returned Array-like object behaves differently from + regular Arrays + https://bugs.webkit.org/show_bug.cgi?id=31689 + + * JavaScriptCore/runtime/RegExpConstructor.cpp: ensure that undefined + values are added to the returned RegExpMatchesArray + +2009-11-24 Oliver Hunt <oliver@apple.com> + + Reviewed by Alexey Proskuryakov. + + JSON.stringify performance on undefined is very poor + https://bugs.webkit.org/show_bug.cgi?id=31839 + + Switch from a UString to a Vector<UChar> when building + the JSON string, allowing us to safely remove the substr-copy + we otherwise did when unwinding an undefined property. + + Also turns out to be a ~5% speedup on stringification. + + * runtime/JSONObject.cpp: + (JSC::Stringifier::StringBuilder::append): + (JSC::Stringifier::stringify): + (JSC::Stringifier::Holder::appendNextProperty): + +2009-11-24 Mark Rowe <mrowe@apple.com> + + Fix production builds where the source tree may be read-only. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2009-11-23 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + Include "config.h" to meet Coding Style Guidelines + https://bugs.webkit.org/show_bug.cgi?id=31792 + + * wtf/unicode/UTF8.cpp: + * wtf/unicode/glib/UnicodeGLib.cpp: + * wtf/unicode/wince/UnicodeWince.cpp: + +2009-11-23 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Streamlined some Math functions where we expect or know the result not + to be representable as an int. + + SunSpider says 0.6% faster. + + * runtime/JSNumberCell.h: + (JSC::JSValue::JSValue): + * runtime/JSValue.h: + (JSC::JSValue::): + (JSC::jsDoubleNumber): + (JSC::JSValue::JSValue): Added a function for making a numeric JSValue + and skipping the "can I encode this as an int?" check, avoiding the + overhead of int <-> double roundtripping and double <-> double comparison + and branching. + + * runtime/MathObject.cpp: + (JSC::mathProtoFuncACos): + (JSC::mathProtoFuncASin): + (JSC::mathProtoFuncATan): + (JSC::mathProtoFuncATan2): + (JSC::mathProtoFuncCos): + (JSC::mathProtoFuncExp): + (JSC::mathProtoFuncLog): + (JSC::mathProtoFuncRandom): + (JSC::mathProtoFuncSin): + (JSC::mathProtoFuncSqrt): + (JSC::mathProtoFuncTan): For these functions, which we expect or know + to produce results not representable as ints, call jsDoubleNumber instead + of jsNumber. + +2009-11-23 Mark Rowe <mrowe@apple.com> + + Unreviewed. Unbreak the regression tests after r51329. + + * API/JSBase.cpp: + (JSEvaluateScript): Null-check clientData before dereferencing it. + * API/JSObjectRef.cpp: + (JSObjectCallAsFunction): Ditto. + +2009-11-23 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Geoff Garen. + + Part 1/3 of <rdar://problem/7377477> REGRESSION: Many web pages fail to render after interesting script runs in isolated world + + Some clients of the JavaScriptCore API expect to be able to make callbacks over the JSC API, + and for this to automagically cause execution to take place in the world associated with the + global object associated with the ExecState (JSContextRef) passed. However this is not how + things work - the world must be explicitly set within WebCore. + + Making this work just for API calls to evaluate & call will be a far from perfect solution, + since direct (non-API) use of JSC still relies on WebCore setting the current world correctly. + A better solution would be to make this all work automagically all throughout WebCore, but this + will require more refactoring. + + Since the API is in JSC but worlds only exist in WebCore, add callbacks on the JSGlobalData::ClientData + to allow it to update the current world on entry/exit via the JSC API. This is temporary duck + tape, and should be removed once the current world no longer needs to be explicitly tracked. + + * API/JSBase.cpp: + (JSEvaluateScript): + * API/JSObjectRef.cpp: + (JSObjectCallAsFunction): + * JavaScriptCore.exp: + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::ClientData::beginningExecution): + (JSC::JSGlobalData::ClientData::completedExecution): + * runtime/JSGlobalData.h: + +2009-11-23 Steve Block <steveblock@google.com> + + Reviewed by Dmitry Titov. + + Adds MainThreadAndroid.cpp with Android-specific WTF threading functions. + https://bugs.webkit.org/show_bug.cgi?id=31807 + + * wtf/android: Added. + * wtf/android/MainThreadAndroid.cpp: Added. + (WTF::timeoutFired): + (WTF::initializeMainThreadPlatform): + (WTF::scheduleDispatchFunctionsOnMainThread): + +2009-11-23 Alexey Proskuryakov <ap@apple.com> + + Reviewed by Brady Eidson. + + https://bugs.webkit.org/show_bug.cgi?id=31748 + Make WebSocketHandleCFNet respect proxy auto-configuration files via CFProxySupport + + * JavaScriptCore.exp: Export callOnMainThreadAndWait. + +2009-11-23 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Symbian] Fix lastIndexOf() for Symbian + https://bugs.webkit.org/show_bug.cgi?id=31773 + + Symbian soft floating point library has problems with operators + comparing NaN to numbers. Without a workaround lastIndexOf() + function does not work. + + Patch developed by David Leong. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncLastIndexOf):Add an extra test + to check for NaN for Symbian. + +2009-11-23 Steve Block <steveblock@google.com> + + Reviewed by Eric Seidel. + + Android port lacks implementation of atomicIncrement and atomicDecrement. + https://bugs.webkit.org/show_bug.cgi?id=31715 + + * wtf/Threading.h: Modified. + (WTF::atomicIncrement): Added Android implementation. + (WTF::atomicDecrement): Added Android implementation. + +2009-11-22 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Unreviewed. + + [Qt] Sort source lists and remove obsolete comments + from the build system. + + * JavaScriptCore.pri: + +2009-11-21 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Eric Seidel. + + [Qt][Mac] Turn on multiple JavaScript threads for QtWebkit on Mac + https://bugs.webkit.org/show_bug.cgi?id=31753 + + * wtf/Platform.h: + +2009-11-19 Steve Block <steveblock@google.com> + + Android port lacks configuration in Platform.h and config.h. + https://bugs.webkit.org/show_bug.cgi?id=31671 + + * wtf/Platform.h: Modified. Added Android-specific configuration. + +2009-11-19 Alexey Proskuryakov <ap@apple.com> + + Reviewed by Darin Adler. + + https://bugs.webkit.org/show_bug.cgi?id=31690 + Make SocketStreamHandleCFNet work on Windows + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * wtf/MainThread.cpp: + (WTF::FunctionWithContext::FunctionWithContext): + (WTF::dispatchFunctionsFromMainThread): + (WTF::callOnMainThreadAndWait): + * wtf/MainThread.h: + Re-add callOnMainThreadAndWait(), which was removed in bug 23926. + +2009-11-19 Dmitry Titov <dimich@chromium.org> + + Reviewed by David Levin. + + isMainThread() on Chromium (Mac and Linux) is so slow it timeouts LayoutTests.. + https://bugs.webkit.org/show_bug.cgi?id=31693 + + * wtf/ThreadingPthreads.cpp: + (WTF::initializeThreading): grab and use the pthread_t of the main thread instead of ThreadIdentifier. + (WTF::isMainThread): Ditto. + +2009-11-19 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Darin Adler. + + Remove HAVE(STRING_H) guard from JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=31668 + + * config.h: + * runtime/UString.cpp: + +2009-11-19 Dumitru Daniliuc <dumi@chromium.org> + + Reviewed by Dmitry Titov. + + Fixing a bug in MessageQueue::removeIf() that leads to an + assertion failure. + + https://bugs.webkit.org/show_bug.cgi?id=31657 + + * wtf/MessageQueue.h: + (WTF::MessageQueue::removeIf): + +2009-11-19 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Darin Adler. + + Remove HAVE(FLOAT_H) guard + https://bugs.webkit.org/show_bug.cgi?id=31661 + + JavaScriptCore has a dependency on float.h, there is + no need to guard float.h. + + * runtime/DatePrototype.cpp: Remove include directive + for float.h as it is included in MathExtras.h already. + * runtime/Operations.cpp: Ditto. + * runtime/UString.cpp: Ditto. + * wtf/dtoa.cpp: Ditto. + * wtf/MathExtras.h: Remove HAVE(FLOAT_H) guard. + * wtf/Platform.h: Ditto. + +2009-11-19 Thiago Macieira <thiago.macieira@nokia.com> + + Reviewed by Simon Hausmann. + + Build fix for 32-bit Sparc machines: these machines are big-endian. + + * wtf/Platform.h: + +2009-11-18 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Remove support for Qt v4.3 or older versions + https://bugs.webkit.org/show_bug.cgi?id=29469 + + * JavaScriptCore.pro: + * jsc.pro: + * wtf/unicode/qt4/UnicodeQt4.h: + +2009-11-18 Kent Tamura <tkent@chromium.org> + + Reviewed by Darin Adler. + + Move UString::from(double) implementation to new + WTF::doubleToStringInJavaScriptFormat(), and expose it because WebCore + code will use it. + https://bugs.webkit.org/show_bug.cgi?id=31330 + + - Introduce new function createRep(const char*, unsigned) and + UString::UString(const char*, unsigned) to reduce 2 calls to strlen(). + - Fix a bug that dtoa() doesn't update *rve if the input value is NaN + or Infinity. + + No new tests because this doesn't change the behavior. + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * runtime/UString.cpp: + (JSC::createRep): + (JSC::UString::UString): + (JSC::UString::from): Move the code to doubleToStringInJavaScriptFormat(). + * runtime/UString.h: + * wtf/dtoa.cpp: + (WTF::dtoa): Fix a bug about rve. + (WTF::append): A helper for doubleToStringInJavaScriptFormat(). + (WTF::doubleToStringInJavaScriptFormat): Move the code from UString::from(double). + * wtf/dtoa.h: + +2009-11-18 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Remove WTF_USE_JAVASCRIPTCORE_BINDINGS as it is no longer used + https://bugs.webkit.org/show_bug.cgi?id=31643 + + * JavaScriptCore.pro: + +2009-11-18 Nate Chapin <japhet@chromium.org> + + Reviewed by Darin Fisher. + + Remove Chromium's unnecessary dependency on wtf's tcmalloc files. + + https://bugs.webkit.org/show_bug.cgi?id=31648 + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + +2009-11-18 Thiago Macieira <thiago.macieira@nokia.com> + + Reviewed by Gavin Barraclough. + + [Qt] Implement symbol hiding for JSC's JIT functions. + + These functions are implemented directly in assembly, so they need the + proper directives to enable/disable visibility. On ELF systems, it's + .hidden, whereas on Mach-O systems (Mac) it's .private_extern. On + Windows, it's not necessary since you have to explicitly export. I + also implemented the AIX idiom, though it's unlikely anyone will + implement AIX/POWER JIT. + https://bugs.webkit.org/show_bug.cgi?id=30864 + + * jit/JITStubs.cpp: + +2009-11-18 Oliver Hunt <oliver@apple.com> + + Reviewed by Alexey Proskuryakov. + + Interpreter may do an out of range access when throwing an exception in the profiler. + https://bugs.webkit.org/show_bug.cgi?id=31635 + + Add bounds check. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::throwException): + +2009-11-18 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Darin Adler. + + Fix the clobber list of cacheFlush for ARM and Thumb2 on Linux + https://bugs.webkit.org/show_bug.cgi?id=31631 + + * jit/ExecutableAllocator.h: + (JSC::ExecutableAllocator::cacheFlush): + +2009-11-18 Harald Fernengel <harald.fernengel@nokia.com> + + Reviewed by Simon Hausmann. + + [Qt] Fix detection of linux-g++ + + Never use "linux-g++*" to check for linux-g++, since this will break embedded + builds which use linux-arm-g++ and friends. Use 'linux*-g++*' to check for any + g++ on linux mkspec. + + * JavaScriptCore.pri: + +2009-11-17 Jon Honeycutt <jhoneycutt@apple.com> + + Add JSContextRefPrivate.h to list of copied files. + + Reviewed by Mark Rowe. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.make: + +2009-11-17 Martin Robinson <martin.james.robinson@gmail.com> + + Reviewed by Adam Barth. + + [GTK] Style cleanup for GOwnPtr + https://bugs.webkit.org/show_bug.cgi?id=31506 + + Remove forward declaration in GOwnPtr and do some style cleanup. + + * wtf/GOwnPtr.cpp: + * wtf/GOwnPtr.h: + (WTF::GOwnPtr::GOwnPtr): + (WTF::GOwnPtr::~GOwnPtr): + (WTF::GOwnPtr::get): + (WTF::GOwnPtr::release): + (WTF::GOwnPtr::outPtr): + (WTF::GOwnPtr::set): + (WTF::GOwnPtr::clear): + (WTF::GOwnPtr::operator*): + (WTF::GOwnPtr::operator->): + (WTF::GOwnPtr::operator!): + (WTF::GOwnPtr::operator UnspecifiedBoolType): + (WTF::GOwnPtr::swap): + (WTF::swap): + (WTF::operator==): + (WTF::operator!=): + (WTF::getPtr): + (WTF::freeOwnedGPtr): + +2009-11-17 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Incorrect use of JavaScriptCore API in DumpRenderTree + https://bugs.webkit.org/show_bug.cgi?id=31577 + + Add assertions to the 'toJS' functions to catch mistakes like + this early. Restructure existing code which blindly passed potentially + null values to toJS when forwarding exceptions so that a null check is + performed first. + + * API/APICast.h: + (toJS): + (toJSForGC): + * API/JSCallbackObjectFunctions.h: + (JSC::::getOwnPropertySlot): + (JSC::::put): + (JSC::::deleteProperty): + (JSC::::construct): + (JSC::::hasInstance): + (JSC::::call): + (JSC::::toNumber): + (JSC::::toString): + (JSC::::staticValueGetter): + (JSC::::callbackGetter): + * API/tests/testapi.c: Fix errors in the API tester. + (MyObject_getProperty): + (MyObject_convertToType): + (EvilExceptionObject_convertToType): + +2009-11-16 Zoltan Herczeg <zherczeg@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + https://bugs.webkit.org/show_bug.cgi?id=31050 + + Minor fixes for JSVALUE32_64: branchConvertDoubleToInt32 + failed on a CortexA8 CPU, but not on a simulator; and + JITCall.cpp modifications was somehow not committed to mainline. + + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::fmrs_r): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::branchConvertDoubleToInt32): + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + +2009-11-16 Joerg Bornemann <joerg.bornemann@trolltech.com> + + Reviewed by Simon Hausmann. + + Fix Qt build on Windows CE 6. + + * JavaScriptCore.pri: Add missing include path. + * wtf/Platform.h: Include ce_time.h for Windows CE 6. + +2009-11-13 Zoltan Herczeg <zherczeg@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + https://bugs.webkit.org/show_bug.cgi?id=31050 + + Adding optimization support for mode JSVALUE32_64 + on ARM systems. + + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_method_check): + (JSC::JIT::compileGetByIdHotPath): + (JSC::JIT::compileGetByIdSlowCase): + (JSC::JIT::emit_op_put_by_id): + +2009-11-14 Zoltan Herczeg <zherczeg@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + https://bugs.webkit.org/show_bug.cgi?id=31050 + + Adding JSVALUE32_64 support for ARM (but not turning it + on by default). All optimizations must be disabled, since + this patch is only the first of a series of patches. + + During the work, a lot of x86 specific code revealed and + made platform independent. + See revisions: 50531 50541 50593 50594 50595 + + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::): + (JSC::ARMAssembler::fdivd_r): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::lshift32): + (JSC::MacroAssemblerARM::neg32): + (JSC::MacroAssemblerARM::rshift32): + (JSC::MacroAssemblerARM::branchOr32): + (JSC::MacroAssemblerARM::set8): + (JSC::MacroAssemblerARM::setTest8): + (JSC::MacroAssemblerARM::loadDouble): + (JSC::MacroAssemblerARM::divDouble): + (JSC::MacroAssemblerARM::convertInt32ToDouble): + (JSC::MacroAssemblerARM::zeroDouble): + * jit/JIT.cpp: + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + * jit/JITStubs.cpp: + * wtf/StdLibExtras.h: + +2009-11-13 Dominik Röttsches <dominik.roettsches@access-company.com> + + Reviewed by Eric Seidel. + + Unify TextBoundaries implementations by only relying on WTF Unicode abstractions + https://bugs.webkit.org/show_bug.cgi?id=31468 + + Adding isAlphanumeric abstraction, required + by TextBoundaries.cpp. + + * wtf/unicode/glib/UnicodeGLib.h: + (WTF::Unicode::isAlphanumeric): + * wtf/unicode/icu/UnicodeIcu.h: + (WTF::Unicode::isAlphanumeric): + +2009-11-13 Norbert Leser <norbert.leser&nokia.com> + + Reviewed by Eric Seidel. + + Added macros for USERINCLUDE paths within symbian blocks + to guarantee inclusion of respective header files from local path + first (to avoid clashes with same names of header files in system include path). + + * JavaScriptCore.pri: + +2009-11-13 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + JSValueProtect and JSValueUnprotect don't protect API wrapper values + https://bugs.webkit.org/show_bug.cgi?id=31485 + + Make JSValueProtect/Unprotect use a new 'toJS' function, 'toJSForGC' that + does not attempt to to strip out API wrapper objects. + + * API/APICast.h: + (toJSForGC): + * API/JSValueRef.cpp: + (JSValueProtect): + (JSValueUnprotect): + * API/tests/testapi.c: + (makeGlobalNumberValue): + (main): + +2009-11-13 İsmail Dönmez <ismail@namtrac.org> + + Reviewed by Antti Koivisto. + + Fix typo, ce_time.cpp should be ce_time.c + + * JavaScriptCore.pri: + +2009-11-12 Steve VanDeBogart <vandebo@chromium.org> + + Reviewed by Adam Barth. + + Calculate the time offset only if we were able to parse + the date string. This saves an IPC in Chromium for + invalid date strings. + https://bugs.webkit.org/show_bug.cgi?id=31416 + + * wtf/DateMath.cpp: + (WTF::parseDateFromNullTerminatedCharacters): + (JSC::parseDateFromNullTerminatedCharacters): + +2009-11-12 Oliver Hunt <oliver@apple.com> + + Rollout r50896 until i can work out why it causes failures. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitReturn): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * parser/Nodes.cpp: + (JSC::EvalNode::emitBytecode): + +2009-11-12 Steve Falkenburg <sfalken@apple.com> + + Reviewed by Stephanie Lewis. + + Remove LIBRARY directive from def file to fix Debug_All target. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2009-11-12 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk> + + Rubber-stamped by Holger Freyther. + + Revert r50204, since it makes DRT crash on 32 bits release builds + for GTK+. + + * wtf/FastMalloc.h: + +2009-11-12 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Start unifying entry logic for function and eval code. + + Eval now uses a ret instruction to end execution, and sets up + a callframe more in line with what we do for function entry. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitReturn): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * parser/Nodes.cpp: + (JSC::EvalNode::emitBytecode): + +2009-11-12 Richard Moe Gustavsen <richard.gustavsen@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Disable pthread_setname_np. + + This allows Qt builds on Mac from 10.6 to run on earlier version + where this symbol is not present. + https://bugs.webkit.org/show_bug.cgi?id=31403 + + * wtf/Platform.h: + +2009-11-12 Thiago Macieira <thiago.macieira@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + [Qt] Fix linking on Linux 32-bit. + + It was missing the ".text" directive at the top of the file, + indicating that code would follow. Without it, the assembler created + "NOTYPE" symbols, which would result in linker errors. + https://bugs.webkit.org/show_bug.cgi?id=30863 + + * jit/JITStubs.cpp: + +2009-11-11 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Alexey Proskuryakov. + + Refactor multiple JavaScriptCore threads + https://bugs.webkit.org/show_bug.cgi?id=31328 + + Remove the id field from the PlatformThread structure + as it is not used. + + * runtime/Collector.cpp: + (JSC::getCurrentPlatformThread): + (JSC::suspendThread): + (JSC::resumeThread): + (JSC::getPlatformThreadRegisters): + +2009-11-10 Geoffrey Garen <ggaren@apple.com> + + Linux build fix: Added an #include for UINT_MAX. + + * runtime/WeakRandom.h: + +2009-11-10 Geoffrey Garen <ggaren@apple.com> + + JavaScriptGlue build fix: Marked a file 'private' instead of 'project'. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2009-11-10 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Gavin "avGni arBalroguch" Barraclough. + + Faster Math.random, based on GameRand. + + SunSpider says 1.4% faster. + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: Added the header to the project. + + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + * runtime/JSGlobalData.h: Use an object to track random number generation + state, initialized to the current time. + + * runtime/MathObject.cpp: + (JSC::MathObject::MathObject): + (JSC::mathProtoFuncRandom): Use the new hotness. + + * runtime/WeakRandom.h: Added. + (JSC::WeakRandom::WeakRandom): + (JSC::WeakRandom::get): + (JSC::WeakRandom::advance): The new hotness. + +2009-11-09 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Imported the v8 DST cache. + + SunSpider says 1.5% faster. + + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::resetDateCache): Reset the DST cache when resetting + other date data. + + * runtime/JSGlobalData.h: + (JSC::DSTOffsetCache::DSTOffsetCache): + (JSC::DSTOffsetCache::reset): Added a struct for the DST cache. + + * wtf/DateMath.cpp: + (WTF::calculateDSTOffsetSimple): + (WTF::calculateDSTOffset): + (WTF::parseDateFromNullTerminatedCharacters): + (JSC::getDSTOffset): + (JSC::gregorianDateTimeToMS): + (JSC::msToGregorianDateTime): + (JSC::parseDateFromNullTerminatedCharacters): + * wtf/DateMath.h: The imported code for probing and updating the cache. + +2009-11-09 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Fixed an edge case that could cause the engine not to notice a timezone + change. + + No test because this case would require manual intervention to change + the timezone during the test. + + SunSpider reports no change. + + * runtime/DateInstanceCache.h: + (JSC::DateInstanceCache::DateInstanceCache): + (JSC::DateInstanceCache::reset): Added a helper function for resetting + this cache. Also, shrank the cache, since we'll be resetting it often. + + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::resetDateCache): Include resetting the DateInstanceCache + in resetting Date data. (Otherwise, a cache hit could bypass a necessary + timezone update check.) + +2009-11-09 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Some manual inlining and constant propogation in Date code. + + SunSpider reports a 0.4% speedup on date-*, no overall speedup. Shark + says some previously evident stalls are now gone. + + * runtime/DateConstructor.cpp: + (JSC::callDate): + * runtime/DateConversion.cpp: + (JSC::formatTime): + (JSC::formatTimeUTC): Split formatTime into UTC and non-UTC variants. + + * runtime/DateConversion.h: + * runtime/DateInstance.cpp: + (JSC::DateInstance::calculateGregorianDateTime): + (JSC::DateInstance::calculateGregorianDateTimeUTC): + * runtime/DateInstance.h: + (JSC::DateInstance::gregorianDateTime): + (JSC::DateInstance::gregorianDateTimeUTC): Split gregorianDateTime into + a UTC and non-UTC variant, and split each variant into a fast inline + case and a slow out-of-line case. + + * runtime/DatePrototype.cpp: + (JSC::formatLocaleDate): + (JSC::dateProtoFuncToString): + (JSC::dateProtoFuncToUTCString): + (JSC::dateProtoFuncToISOString): + (JSC::dateProtoFuncToDateString): + (JSC::dateProtoFuncToTimeString): + (JSC::dateProtoFuncGetFullYear): + (JSC::dateProtoFuncGetUTCFullYear): + (JSC::dateProtoFuncToGMTString): + (JSC::dateProtoFuncGetMonth): + (JSC::dateProtoFuncGetUTCMonth): + (JSC::dateProtoFuncGetDate): + (JSC::dateProtoFuncGetUTCDate): + (JSC::dateProtoFuncGetDay): + (JSC::dateProtoFuncGetUTCDay): + (JSC::dateProtoFuncGetHours): + (JSC::dateProtoFuncGetUTCHours): + (JSC::dateProtoFuncGetMinutes): + (JSC::dateProtoFuncGetUTCMinutes): + (JSC::dateProtoFuncGetSeconds): + (JSC::dateProtoFuncGetUTCSeconds): + (JSC::dateProtoFuncGetTimezoneOffset): + (JSC::setNewValueFromTimeArgs): + (JSC::setNewValueFromDateArgs): + (JSC::dateProtoFuncSetYear): + (JSC::dateProtoFuncGetYear): Updated for the gregorianDateTime change above. + +2009-11-09 Geoffrey Garen <ggaren@apple.com> + + Build fix: export a new symbol. + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2009-11-09 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam "Home Wrecker" Weinig. + + Added a tiny cache for Date parsing. + + SunSpider says 1.2% faster. + + * runtime/DateConversion.cpp: + (JSC::parseDate): Try to reuse the last parsed Date, if present. + + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::resetDateCache): + * runtime/JSGlobalData.h: Added storage for last parsed Date. Refactored + this code to make resetting the date cache easier. + + * runtime/JSGlobalObject.h: + (JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Updated for + refactoring. + + * wtf/DateMath.cpp: + (JSC::parseDateFromNullTerminatedCharacters): + * wtf/DateMath.h: Changed ExecState to be first parameter, as is the JSC custom. + +2009-11-09 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Can cache prototype lookups on uncacheable dictionaries. + https://bugs.webkit.org/show_bug.cgi?id=31198 + + Replace fromDictionaryTransition with flattenDictionaryObject and + flattenDictionaryStructure. This change is necessary as we need to + guarantee that our attempt to convert away from a dictionary structure + will definitely succeed, and in some cases this requires mutating the + object storage itself. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::tryCacheGetByID): + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCacheGetByID): + (JSC::DEFINE_STUB_FUNCTION): + * runtime/BatchedTransitionOptimizer.h: + (JSC::BatchedTransitionOptimizer::~BatchedTransitionOptimizer): + * runtime/JSObject.h: + (JSC::JSObject::flattenDictionaryObject): + * runtime/Operations.h: + (JSC::normalizePrototypeChain): + * runtime/Structure.cpp: + (JSC::Structure::flattenDictionaryStructure): + (JSC::comparePropertyMapEntryIndices): + * runtime/Structure.h: + +2009-11-09 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Not reviewed, build fix. + + Remove extra character from r50701. + + * JavaScriptCore.pri: + +2009-11-09 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Not reviewed, build fix. + + Revert r50695 because it broke QtWebKit (clean builds). + + * JavaScriptCore.pri: + +2009-11-09 Norbert Leser <norbert.leser@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + Prepended $$PWD to GENERATED_SOURCES_DIR to avoid potential ambiguities when included from WebCore.pro. + Some preprocessors consider this GENERATED_SOURCES_DIR relative to current invoking dir (e.g., ./WebCore), + and not the working dir of JavaCriptCore.pri (i.e., ../JavaScriptCore/). + + * JavaScriptCore.pri: + +2009-11-09 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Kenneth Rohde Christiansen. + + Use explicit parentheses to silence gcc 4.4 -Wparentheses warnings + https://bugs.webkit.org/show_bug.cgi?id=31040 + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + +2009-11-08 David Levin <levin@chromium.org> + + Reviewed by NOBODY (speculative snow leopard and windows build fixes). + + * wtf/DateMath.cpp: + (WTF::parseDateFromNullTerminatedCharacters): + (JSC::gregorianDateTimeToMS): + (JSC::msToGregorianDateTime): + (JSC::parseDateFromNullTerminatedCharacters): + * wtf/DateMath.h: + (JSC::GregorianDateTime::GregorianDateTime): + +2009-11-08 David Levin <levin@chromium.org> + + Reviewed by NOBODY (chromium build fix). + + Hopefully, the last build fix. + + Create better separation in DateMath about the JSC + and non-JSC portions. Also, only expose the non-JSC + version in the exports. + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * wtf/DateMath.cpp: + (WTF::parseDateFromNullTerminatedCharacters): + (JSC::getUTCOffset): + (JSC::gregorianDateTimeToMS): + (JSC::msToGregorianDateTime): + (JSC::parseDateFromNullTerminatedCharacters): + * wtf/DateMath.h: + (JSC::gmtoffset): + +2009-11-08 David Levin <levin@chromium.org> + + Reviewed by NOBODY (chromium build fix). + + For the change in DateMath. + + * config.h: + * wtf/DateMath.cpp: + +2009-11-06 Geoffrey Garen <ggaren@apple.com> + + Windows build fix: export some symbols. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2009-11-06 Geoffrey Garen <ggaren@apple.com> + + Build fix: updated export file. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + +2009-11-06 Geoffrey Garen <ggaren@apple.com> + + Build fix: added some #includes. + + * wtf/CurrentTime.h: + * wtf/DateMath.h: + +2009-11-06 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=31197 + Implemented a timezone cache not based on Mac OS X's notify_check API. + + If the VM calculates the local timezone offset from UTC, it caches the + result until the end of the current VM invocation. (We don't want to cache + forever, because the user's timezone may change over time.) + + This removes notify_* overhead on Mac, and, more significantly, removes + OS time and date call overhead on non-Mac platforms. + + ~8% speedup on Date microbenchmark on Mac. SunSpider reports maybe a tiny + speedup on Mac. (Speedup on non-Mac platforms should be even more noticeable.) + + * JavaScriptCore.exp: + + * interpreter/CachedCall.h: + (JSC::CachedCall::CachedCall): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * runtime/JSGlobalObject.h: + (JSC::DynamicGlobalObjectScope::DynamicGlobalObjectScope): Made the + DynamicGlobalObjectScope constructor responsible for checking whether a + dynamicGlobalObject has already been set. This eliminated some duplicate + client code, and allowed me to avoid adding even more duplicate client + code. Made DynamicGlobalObjectScope responsible for resetting the + local timezone cache upon first entry to the VM. + + * runtime/DateConstructor.cpp: + (JSC::constructDate): + (JSC::callDate): + (JSC::dateParse): + (JSC::dateUTC): + * runtime/DateConversion.cpp: + (JSC::parseDate): + * runtime/DateConversion.h: + * runtime/DateInstance.cpp: + (JSC::DateInstance::gregorianDateTime): + * runtime/DateInstance.h: + * runtime/DateInstanceCache.h: + * runtime/DatePrototype.cpp: + (JSC::setNewValueFromTimeArgs): + (JSC::setNewValueFromDateArgs): + (JSC::dateProtoFuncSetYear): + * runtime/InitializeThreading.cpp: + (JSC::initializeThreadingOnce): + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + * runtime/JSGlobalData.h: + * wtf/DateMath.cpp: + (WTF::getCurrentUTCTime): + (WTF::getCurrentUTCTimeWithMicroseconds): + (WTF::getLocalTime): + (JSC::getUTCOffset): Use the new cache. Also, see below. + (JSC::gregorianDateTimeToMS): + (JSC::msToGregorianDateTime): + (JSC::initializeDates): + (JSC::parseDateFromNullTerminatedCharacters): Simplified the way this function + accounts for the local timezone offset, to accomodate our new caching API, + and a (possibly misguided) caller in WebCore. Also, see below. + * wtf/DateMath.h: + (JSC::GregorianDateTime::GregorianDateTime): Moved most of the code in + DateMath.* into the JSC namespace. The code needed to move so it could + naturally interact with ExecState and JSGlobalData to support caching. + Logically, it seemed right to move it, too, since this code is not really + as low-level as the WTF namespace might imply -- it implements a set of + date parsing and conversion quirks that are finely tuned to the JavaScript + language. Also removed the Mac OS X notify_* infrastructure. + + * wtf/CurrentTime.h: + (WTF::currentTimeMS): + (WTF::getLocalTime): Moved the rest of the DateMath code here, and renamed + it to make it consistent with WTF's currentTime function. + +2009-11-06 Gabor Loki <loki@inf.u-szeged.hu> + + Unreviewed trivial buildfix after r50595. + + Rename the remaining rshiftPtr calls to rshift32 + + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_rshift): + * jit/JITInlineMethods.h: + (JSC::JIT::emitFastArithImmToInt): + +2009-11-06 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Tidy up the shift methods on the macro-assembler interface. + + Currently behaviour of shifts of a magnitude > 0x1f is undefined. + Instead defined that all shifts are masked to this range. This makes a lot of + practical sense, both since having undefined behaviour is not particularly + desirable, and because this behaviour is commonly required (particularly since + it is required bt ECMA-262 for shifts). + + Update the ARM assemblers to provide this behaviour. Remove (now) redundant + masks from JITArithmetic, and remove rshiftPtr (this was used in case that + could be rewritten in a simpler form using rshift32, only optimized JSVALUE32 + on x86-64, which uses JSVALUE64!) + + * assembler/MacroAssembler.h: + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::lshift32): + (JSC::MacroAssemblerARM::rshift32): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::lshift32): + (JSC::MacroAssemblerARMv7::rshift32): + * assembler/MacroAssemblerX86_64.h: + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_lshift): + (JSC::JIT::emit_op_rshift): + +2009-11-05 Gavin Barraclough <barraclough@apple.com> + + Rubber Stamped by Oliver Hunt. + + Remove a magic number (1) from the JIT, instead compute the value with OBJECT_OFFSET. + + * jit/JITInlineMethods.h: + (JSC::JIT::emitPutJITStubArg): + (JSC::JIT::emitPutJITStubArgConstant): + (JSC::JIT::emitGetJITStubArg): + (JSC::JIT::emitPutJITStubArgFromVirtualRegister): + * jit/JITStubCall.h: + (JSC::JITStubCall::JITStubCall): + (JSC::JITStubCall::getArgument): + * jit/JITStubs.h: + +2009-11-05 Zoltan Herczeg <zherczeg@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + https://bugs.webkit.org/show_bug.cgi?id=31159 + Fix branchDouble behaviour on ARM THUMB2 JIT. + + The x86 branchDouble behaviour is reworked, and all JIT + ports should follow the x86 port. See bug 31104 and 31151 + + This patch contains a fix for the traditional ARM port + + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::): + (JSC::ARMAssembler::fmrs_r): + (JSC::ARMAssembler::ftosid_r): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::): + (JSC::MacroAssemblerARM::branchDouble): + (JSC::MacroAssemblerARM::branchConvertDoubleToInt32): + +2009-11-05 Chris Jerdonek <chris.jerdonek@gmail.com> + + Reviewed by Eric Seidel. + + Removed the "this is part of the KDE project" comments from + all *.h, *.cpp, *.idl, and *.pm files. + + https://bugs.webkit.org/show_bug.cgi?id=31167 + + The maintenance and architecture page in the project wiki lists + this as a task. + + This change includes no changes or additions to test cases + since the change affects only comments. + + * wtf/wince/FastMallocWince.h: + +2009-11-05 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Use ARMv7 specific encoding for immediate constants on ARMv7 target + https://bugs.webkit.org/show_bug.cgi?id=31060 + + * assembler/ARMAssembler.cpp: + (JSC::ARMAssembler::getOp2): Use INVALID_IMM + (JSC::ARMAssembler::getImm): Use encodeComplexImm for complex immediate + (JSC::ARMAssembler::moveImm): Ditto. + (JSC::ARMAssembler::encodeComplexImm): Encode a constant by one or two + instructions or a PC relative load. + * assembler/ARMAssembler.h: Use INVALID_IMM if a constant cannot be + encoded as an immediate constant. + (JSC::ARMAssembler::): + (JSC::ARMAssembler::movw_r): 16-bit immediate load + (JSC::ARMAssembler::movt_r): High halfword 16-bit immediate load + (JSC::ARMAssembler::getImm16Op2): Encode immediate constant for + movw_r and mowt_r + +2009-11-04 Mark Mentovai <mark@chromium.org> + + Reviewed by Mark Rowe. + + Provide TARGETING_TIGER and TARGETING_LEOPARD as analogues to + BUILDING_ON_TIGER and BUILDING_ON_LEOPARD. The TARGETING_ macros + consider the deployment target; the BUILDING_ON_ macros consider the + headers being built against. + + * wtf/Platform.h: + +2009-11-04 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=31151 + Fix branchDouble behaviour on ARM THUMB2 JIT. + + The ARMv7 JIT is currently using ARMv7Assembler::ConditionEQ to branch + for DoubleEqualOrUnordered, however this is incorrect – ConditionEQ won't + branch on unordered operands. Similarly, DoubleLessThanOrUnordered & + DoubleLessThanOrEqualOrUnordered use ARMv7Assembler::ConditionLO & + ARMv7Assembler::ConditionLS, whereas they should be using + ARMv7Assembler::ConditionLT & ARMv7Assembler::ConditionLE. + + Fix these, and fill out the missing DoubleConditions. + + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::): + (JSC::MacroAssemblerARMv7::branchDouble): + +2009-11-04 Gavin Barraclough <barraclough@apple.com> + + Rubber Stamped by Oliver Hunt. + + Enable native call optimizations on ARMv7. (Existing ARM_TRADITIONAL + implementation was generic, worked perfectly, just needed turning on). + + * jit/JITOpcodes.cpp: + * wtf/Platform.h: + +2009-11-04 Gavin Barraclough <barraclough@apple.com> + + Rubber Stamped by Mark Rowe, Oliver Hunt, and Sam Weinig. + + Add a missing assert to the ARMv7 JIT. + + * assembler/ARMv7Assembler.h: + (JSC::ARMThumbImmediate::ARMThumbImmediate): + +2009-11-04 Mark Rowe <mrowe@apple.com> + + Rubber-stamped by Oliver Hunt. + + Remove bogus op_ prefix on dumped version of three opcodes. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + +2009-11-04 Mark Rowe <mrowe@apple.com> + + Reviewed by Sam Weinig. + + Fix dumping of constants in bytecode so that they aren't printed as large positive register numbers. + + We do this by having the registerName function return information about the constant if the register + number corresponds to a constant. This requires that registerName, and several functions that call it, + be converted to member functions of CodeBlock so that the constant value can be retrieved. The + ExecState also needs to be threaded down through these functions so that it can be passed on to + constantName when needed. + + * bytecode/CodeBlock.cpp: + (JSC::constantName): + (JSC::CodeBlock::registerName): + (JSC::CodeBlock::printUnaryOp): + (JSC::CodeBlock::printBinaryOp): + (JSC::CodeBlock::printConditionalJump): + (JSC::CodeBlock::printGetByIdOp): + (JSC::CodeBlock::printPutByIdOp): + (JSC::CodeBlock::dump): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::isConstantRegisterIndex): + +2009-11-04 Pavel Heimlich <tropikhajma@gmail.com> + + Reviewed by Alexey Proskuryakov. + + https://bugs.webkit.org/show_bug.cgi?id=30647 + Solaris build failure due to strnstr. + + * wtf/StringExtras.h: Enable strnstr on Solaris, too. + +2009-11-04 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=31104 + Refactor x86-specific behaviour out of the JIT. + + - Add explicit double branch conditions for ordered and unordered comparisons (presently the brehaviour is a mix). + - Refactor double to int conversion out into the MacroAssembler. + - Remove broken double to int conversion for !JSVALUE32_64 builds - this code was broken and slowing us down, fixing it showed it not to be an improvement. + - Remove exclusion of double to int conversion from (1 % X) cases in JSVALUE32_64 builds - if this was of benefit this is no longer the case; simplify. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::): + (JSC::MacroAssemblerX86Common::convertInt32ToDouble): + (JSC::MacroAssemblerX86Common::branchDouble): + (JSC::MacroAssemblerX86Common::branchConvertDoubleToInt32): + * jit/JITArithmetic.cpp: + (JSC::JIT::emitBinaryDoubleOp): + (JSC::JIT::emit_op_div): + (JSC::JIT::emitSlow_op_jnless): + (JSC::JIT::emitSlow_op_jnlesseq): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_jfalse): + +2009-11-04 Mark Mentovai <mark@chromium.org> + + Reviewed by Eric Seidel. + + Remove BUILDING_ON_LEOPARD from JavaScriptCore.gyp. This is supposed + to be set as needed only in wtf/Platform.h. + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + +2009-11-02 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + REGRESSION (r48573): JSC may incorrectly cache chain lookups with a dictionary at the head of the chain + https://bugs.webkit.org/show_bug.cgi?id=31045 + + Add guards to prevent caching of prototype chain lookups with dictionaries at the + head of the chain. Also add a few tighter assertions to cached prototype lookups + to catch this in future. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::tryCacheGetByID): + (JSC::Interpreter::privateExecute): + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCacheGetByID): + +2009-11-02 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Darin Adler. + + PLATFORM(CF) should be set when building for Qt on Darwin + https://bugs.webkit.org/show_bug.cgi?id=23671 + + * wtf/Platform.h: Turn on CF support if both QT and DARWIN + platforms are defined. + +2009-11-02 Dmitry Titov <dimich@chromium.org> + + Reviewed by David Levin. + + Remove threadsafe refcounting from tasks used with WTF::MessageQueue. + https://bugs.webkit.org/show_bug.cgi?id=30612 + + * wtf/MessageQueue.h: + (WTF::MessageQueue::alwaysTruePredicate): + (WTF::MessageQueue::~MessageQueue): + (WTF::MessageQueue::append): + (WTF::MessageQueue::appendAndCheckEmpty): + (WTF::MessageQueue::prepend): + (WTF::MessageQueue::waitForMessage): + (WTF::MessageQueue::waitForMessageFilteredWithTimeout): + (WTF::MessageQueue::tryGetMessage): + (WTF::MessageQueue::removeIf): + The MessageQueue is changed to act as a queue of OwnPtr<DataType>. It takes ownership + of posted tasks and passes it to the new owner (in another thread) when the task is fetched. + All methods have arguments of type PassOwnPtr<DataType> and return the same type. + + * wtf/Threading.cpp: + (WTF::createThread): + Superficial change to trigger rebuild of JSC project on Windows, + workaround for https://bugs.webkit.org/show_bug.cgi?id=30890 + +2009-10-30 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Fixed failing layout test: restore a special case I accidentally deleted. + + * runtime/DatePrototype.cpp: + (JSC::setNewValueFromDateArgs): In the case of applying a change to a date + that is NaN, reset the date to 0 *and* then apply the change; don't just + reset the date to 0. + +2009-10-30 Geoffrey Garen <ggaren@apple.com> + + Windows build fix: update for object-to-pointer change. + + * runtime/DatePrototype.cpp: + (JSC::formatLocaleDate): + +2009-10-29 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Darin Adler. + + https://bugs.webkit.org/show_bug.cgi?id=30942 + Use pointers instead of copies to pass GregorianDateTime objects around. + + SunSpider reports a shocking 4.5% speedup on date-format-xparb, and 1.3% + speedup on date-format-tofte. + + * runtime/DateInstance.cpp: + (JSC::DateInstance::gregorianDateTime): + * runtime/DateInstance.h: + * runtime/DatePrototype.cpp: + (JSC::formatLocaleDate): + (JSC::dateProtoFuncToString): + (JSC::dateProtoFuncToUTCString): + (JSC::dateProtoFuncToISOString): + (JSC::dateProtoFuncToDateString): + (JSC::dateProtoFuncToTimeString): + (JSC::dateProtoFuncGetFullYear): + (JSC::dateProtoFuncGetUTCFullYear): + (JSC::dateProtoFuncToGMTString): + (JSC::dateProtoFuncGetMonth): + (JSC::dateProtoFuncGetUTCMonth): + (JSC::dateProtoFuncGetDate): + (JSC::dateProtoFuncGetUTCDate): + (JSC::dateProtoFuncGetDay): + (JSC::dateProtoFuncGetUTCDay): + (JSC::dateProtoFuncGetHours): + (JSC::dateProtoFuncGetUTCHours): + (JSC::dateProtoFuncGetMinutes): + (JSC::dateProtoFuncGetUTCMinutes): + (JSC::dateProtoFuncGetSeconds): + (JSC::dateProtoFuncGetUTCSeconds): + (JSC::dateProtoFuncGetTimezoneOffset): + (JSC::setNewValueFromTimeArgs): + (JSC::setNewValueFromDateArgs): + (JSC::dateProtoFuncSetYear): + (JSC::dateProtoFuncGetYear): Renamed getGregorianDateTime to gregorianDateTime, + since it no longer has an out parameter. Uses 0 to indicate invalid dates. + +2009-10-30 Zoltan Horvath <zoltan@webkit.org> + + Reviewed by Darin Adler. + + Allow custom memory allocation control for JavaScriptCore's ListHashSet + https://bugs.webkit.org/show_bug.cgi?id=30853 + + Inherits ListHashSet class from FastAllocBase because it is + instantiated by 'new' in WebCore/rendering/RenderBlock.cpp:1813. + + * wtf/ListHashSet.h: + +2009-10-30 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Regression: crash enumerating properties of an object with getters or setters + https://bugs.webkit.org/show_bug.cgi?id=30948 + + Add a guard to prevent us trying to cache property enumeration on + objects with getters or setters. + + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::create): + +2009-10-30 Roland Steiner <rolandsteiner@chromium.org> + + Reviewed by Eric Seidel. + + Remove ENABLE_RUBY guards as discussed with Dave Hyatt and Maciej Stachowiak. + + Bug 28420 - Implement HTML5 <ruby> rendering + (https://bugs.webkit.org/show_bug.cgi?id=28420) + + No new tests (no functional change). + + * Configurations/FeatureDefines.xcconfig: + +2009-10-29 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + REGRESSION (r50218-r50262): E*TRADE accounts page is missing content + https://bugs.webkit.org/show_bug.cgi?id=30947 + <rdar://problem/7348833> + + The logic for flagging that a structure has non-enumerable properties + was in addPropertyWithoutTransition, rather than in the core Structure::put + method. Despite this I was unable to produce a testcase that caused + the failure that etrade was experiencing, but the new assertion in + getEnumerablePropertyNames triggers on numerous layout tests without + the fix, so in effecti all for..in enumeration in any test ends up + doing the required consistency check. + + * runtime/Structure.cpp: + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::put): + (JSC::Structure::getEnumerablePropertyNames): + (JSC::Structure::checkConsistency): + +2009-10-29 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Add cacheFlush support for Thumb-2 on Linux + https://bugs.webkit.org/show_bug.cgi?id=30865 + + * jit/ExecutableAllocator.h: + (JSC::ExecutableAllocator::cacheFlush): + +2009-10-28 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + JSC JIT on ARMv7 cannot link jumps >16Mb range + https://bugs.webkit.org/show_bug.cgi?id=30891 + + Start planing all relative jumps as move-32-bit-immediate-to-register-BX. + In the cases where the jump would fall within a relative jump range, use a relative jump. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * assembler/ARMv7Assembler.h: + (JSC::ARMv7Assembler::~ARMv7Assembler): + (JSC::ARMv7Assembler::LinkRecord::LinkRecord): + (JSC::ARMv7Assembler::): + (JSC::ARMv7Assembler::executableCopy): + (JSC::ARMv7Assembler::linkJump): + (JSC::ARMv7Assembler::relinkJump): + (JSC::ARMv7Assembler::setInt32): + (JSC::ARMv7Assembler::isB): + (JSC::ARMv7Assembler::isBX): + (JSC::ARMv7Assembler::isMOV_imm_T3): + (JSC::ARMv7Assembler::isMOVT): + (JSC::ARMv7Assembler::isNOP_T1): + (JSC::ARMv7Assembler::isNOP_T2): + (JSC::ARMv7Assembler::linkJumpAbsolute): + (JSC::ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst): + (JSC::ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond): + (JSC::ARMv7Assembler::ARMInstructionFormatter::twoWordOp5i6Imm4Reg4EncodedImm): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::makeJump): + (JSC::MacroAssemblerARMv7::makeBranch): + * jit/JIT.h: + * wtf/Platform.h: + +2009-10-28 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Improve for..in enumeration performance + https://bugs.webkit.org/show_bug.cgi?id=30887 + + Improve indexing of an object with a for..in iterator by + identifying cases where get_by_val is being used with a iterator + as the subscript and replace it with a new get_by_pname + bytecode. get_by_pname then optimizes lookups that directly access + the base object. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetByVal): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::pushOptimisedForIn): + (JSC::BytecodeGenerator::popOptimisedForIn): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::compileGetDirectOffset): + (JSC::JIT::emit_op_get_by_pname): + (JSC::JIT::emitSlow_op_get_by_pname): + * parser/Nodes.cpp: + (JSC::ForInNode::emitBytecode): + * runtime/JSObject.h: + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::create): + * runtime/JSPropertyNameIterator.h: + (JSC::JSPropertyNameIterator::getOffset): + (JSC::JSPropertyNameIterator::JSPropertyNameIterator): + * runtime/JSValue.h: + (JSC::JSValue::): + * runtime/Structure.cpp: + (JSC::Structure::addPropertyTransition): + (JSC::Structure::changePrototypeTransition): + (JSC::Structure::despecifyFunctionTransition): + (JSC::Structure::addAnonymousSlotsTransition): + (JSC::Structure::getterSetterTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::addPropertyWithoutTransition): + Track the existence (or not) of non-enumerable properties. + * runtime/Structure.h: + (JSC::Structure::propertyStorageCapacity): + (JSC::Structure::propertyStorageSize): + (JSC::Structure::hasNonEnumerableProperties): + (JSC::Structure::hasAnonymousSlots): + +2009-10-28 Dmitry Titov <dimich@chromium.org> + + Not reviewed, attemp to fix Windows build. + + Touch the cpp file to cause recompile. + + * wtf/Threading.cpp: + (WTF::threadEntryPoint): + +2009-10-28 Dmitry Titov <dimich@chromium.org> + + Reviewed by David Levin. + + https://bugs.webkit.org/show_bug.cgi?id=30805 + Add MessageQueue::removeIf(Predicate&) to remove certain tasks without pulling them from the queue. + Existing Database tests cover this since Database removes tasks when it is stopped. + + * wtf/MessageQueue.h: + (WTF::::removeIf): + +2009-10-28 Afonso R. Costa Jr. <afonso.costa@openbossa.org> + + Reviewed by Oliver Hunt. + + [Qt] Enable YARR when YARR_JIT is enabled + https://bugs.webkit.org/show_bug.cgi?id=30730 + + When enabling or disabling JIT using JAVASCRIPTCORE_JIT, the ENABLE_YARR should + be toggled also. + + * JavaScriptCore.pri: + +2009-10-24 Martin Robinson <martin.james.robinson@gmail.com> + + Reviewed by Oliver Hunt. + + Fix strict aliasing warning by switching reinterpret_cast to bitwise_cast. + + strict-aliasing warnings in JSFunction.h + https://bugs.webkit.org/show_bug.cgi?id=27869 + + * runtime/JSFunction.h: + (JSC::JSFunction::nativeFunction): + (JSC::JSFunction::scopeChain): + (JSC::JSFunction::setScopeChain): + (JSC::JSFunction::setNativeFunction): + +2009-10-28 Jan-Arve Sæther <jan-arve.saether@nokia.com> + + Reviewed by Tor Arne Vestbø. + + Build-fix for 64-bit Windows + + * wtf/Platform.h: Make sure to use WTF_USE_JSVALUE64 + +2009-10-28 Gavin Barraclough <barraclough@apple.com> + + Reviewed by NOBODY (build fix!). + + * jit/JIT.h: + +2009-10-26 Holger Hans Peter Freyther <zecke@selfish.org> + + Rubber-stamped by Darin Adler. + + Export fastMalloc, fastCalloc, fastRealloc and fastFree on GCC/Unix + https://bugs.webkit.org/show_bug.cgi?id=30769 + + When using -fvisibility=hidden to hide all internal symbols by default + the malloc symbols will be hidden as well. For memory instrumentation + it is needed to provide an instrumented version of these symbols and + override the normal routines and by changing the visibility back to + default this becomes possible. + + The only other solution would be to use system malloc instead of the + TCmalloc implementation but this will not allow to analyze memory + behavior with the default allocator. + + * wtf/FastMalloc.h: Define WTF_FAST_MALLOC_EXPORT for GCC and !darwin + +2009-10-27 Gavin Barraclough <barraclough@apple.com> + + Rubber Stamped by Samuel Q. Weinig. + + Make the asserts protecting the offsets in the JIT more descriptive. + + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_method_check): + (JSC::JIT::compileGetByIdHotPath): + (JSC::JIT::compileGetByIdSlowCase): + (JSC::JIT::emit_op_put_by_id): + +2009-10-27 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + A little bit of refactoring in the date code. + + * JavaScriptCore.exp: Don't export this unused symbol. + + * runtime/DateConstructor.cpp: + (JSC::constructDate): + + * runtime/DateInstance.cpp: + (JSC::DateInstance::DateInstance): + * runtime/DateInstance.h: Removed some unused functions. Changed the default + constructor to ensure that a DateInstance is always initialized. + + * runtime/DatePrototype.cpp: + (JSC::DatePrototype::DatePrototype): Pass an initializer to our constructor, + since it now requires one. + + * wtf/DateMath.cpp: + (WTF::msToGregorianDateTime): Only compute our offset from UTC if our + output will require it. Otherwise, our offset is 0. + +2009-10-27 Geoffrey Garen <ggaren@apple.com> + + Build fix: Mark DateInstaceCache.h private, so other frameworks can see it. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2009-10-27 Geoffrey Garen <ggaren@apple.com> + + Build fix: re-readded this file. + + * runtime/DateInstanceCache.h: Added. + (JSC::DateInstanceData::create): + (JSC::DateInstanceData::DateInstanceData): + (JSC::DateInstanceCache::DateInstanceCache): + (JSC::DateInstanceCache::add): + (JSC::DateInstanceCache::lookup): + +2009-10-27 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Darin Adler and Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=30800 + Cache recently computed date data. + + SunSpider reports a ~0.5% speedup, mostly from date-format-tofte.js. + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCore.xcodeproj/project.pbxproj: Added new file. + + * runtime/DateInstance.cpp: + (JSC::DateInstance::DateInstance): + (JSC::DateInstance::getGregorianDateTime): Use the shared cache. + + * runtime/DateInstance.h: Renamed m_cache to m_data, to avoid the confusion + of a "cache cache". + + * runtime/DatePrototype.cpp: + (JSC::formatLocaleDate): + (JSC::dateProtoFuncToString): + (JSC::dateProtoFuncToUTCString): + (JSC::dateProtoFuncToISOString): + (JSC::dateProtoFuncToDateString): + (JSC::dateProtoFuncToTimeString): + (JSC::dateProtoFuncGetFullYear): + (JSC::dateProtoFuncGetUTCFullYear): + (JSC::dateProtoFuncToGMTString): + (JSC::dateProtoFuncGetMonth): + (JSC::dateProtoFuncGetUTCMonth): + (JSC::dateProtoFuncGetDate): + (JSC::dateProtoFuncGetUTCDate): + (JSC::dateProtoFuncGetDay): + (JSC::dateProtoFuncGetUTCDay): + (JSC::dateProtoFuncGetHours): + (JSC::dateProtoFuncGetUTCHours): + (JSC::dateProtoFuncGetMinutes): + (JSC::dateProtoFuncGetUTCMinutes): + (JSC::dateProtoFuncGetSeconds): + (JSC::dateProtoFuncGetUTCSeconds): + (JSC::dateProtoFuncGetTimezoneOffset): + (JSC::setNewValueFromTimeArgs): + (JSC::setNewValueFromDateArgs): + (JSC::dateProtoFuncSetYear): + (JSC::dateProtoFuncGetYear): Pass an ExecState to these functions, so they + can access the DateInstanceCache. + + * runtime/JSGlobalData.h: Keep a DateInstanceCache. + +2009-10-27 James Robinson <jamesr@chromium.org> + + Reviewed by Darin Fisher. + + Ensures that JavaScriptCore/wtf/CurrentTime.cpp is not built in PLATFORM(CHROMIUM) builds. + + Chromium uses a different method to calculate the current time than is used in + JavaScriptCore/wtf/CurrentTime.cpp. This can lead to time skew when calls to currentTime() and Chromium's time + function are mixed. In particular, timers can get scheduled in the past which leads to 100% CPU use. + See http://code.google.com/p/chromium/issues/detail?id=25892 for an example. + + https://bugs.webkit.org/show_bug.cgi?id=30833 + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + * wtf/CurrentTime.cpp: + +2009-10-27 Peter Varga <pvarga@inf.u-szeged.hu> + + Rubber-stamped by Tor Arne Vestbø. + + Fix typo in RegexInterpreter.cpp and RegexJIT.cpp alterantive to + alternative. + + * yarr/RegexInterpreter.cpp: + (JSC::Yarr::ByteCompiler::alternativeBodyDisjunction): + (JSC::Yarr::ByteCompiler::alternativeDisjunction): + (JSC::Yarr::ByteCompiler::emitDisjunction): + * yarr/RegexJIT.cpp: + (JSC::Yarr::RegexGenerator::generateDisjunction): + +2009-10-26 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Darin Adler. + + Make .rc files compile on Windows without depending on MFC headers + https://bugs.webkit.org/show_bug.cgi?id=30750 + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.rc: Use + winresrc.h because it exists even when MFC is not installed, and is + all that's needed here. + +2009-10-26 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + The thunkReturnAddress is on JITStackFrame on ARM JIT as well + https://bugs.webkit.org/show_bug.cgi?id=30782 + + Move the thunkReturnAddress from top of the stack into the JITStackFrame + structure. This is a requirement for JSValue32_64 support on ARM. + + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::ret): Return with link register + (JSC::MacroAssemblerARM::prepareCall): Store the return address in link register + * jit/JIT.h: Remove unused ctiReturnRegister + * jit/JITInlineMethods.h: Same as ARMv7 + (JSC::JIT::restoreArgumentReference): Ditto. + (JSC::JIT::restoreArgumentReferenceForTrampoline): Ditto. + * jit/JITOpcodes.cpp: Remove ctiReturnRegister related instruction + * jit/JITStubs.cpp: Store thunkReturnAddress on JITStackFrame. Use + small trampoline functions which handle return addresses for each + CTI_STUB_FUNCTION. + * jit/JITStubs.h: Store thunkReturnAddress on JITStackFrame + (JSC::JITStackFrame::returnAddressSlot): Return with the address of thunkReturnAddress + * yarr/RegexJIT.cpp: + (JSC::Yarr::RegexGenerator::generateEnter): Remove the unnecessary instruction + +2009-10-26 Steve Block <steveblock@google.com> + + Reviewed by Darin Adler. + + Adds ability to disable ReadWriteLock on platforms (eg Android) that use pthreads but do not support pthread_rwlock. + https://bugs.webkit.org/show_bug.cgi?id=30713 + + * wtf/Platform.h: Modified. Defines HAVE_PTHREAD_RWLOCK for all platforms currently using pthreads. + * wtf/Threading.h: Modified. Use pthread_rwlock_t only when HAVE_PTHREAD_RWLOCK is defined. + * wtf/ThreadingPthreads.cpp: Modified. Build ReadWriteLock methods only when HAVE_PTHREAD_RWLOCK is defined. + +2009-10-24 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Holger Freyther. + + [Qt] [Symbian] Set the capability and memory required to run QtWebKit for Symbian + https://bugs.webkit.org/show_bug.cgi?id=30476 + + Assign ReadUserData WriteUserData NetworkServices Symbian capabilities + to jsc.exe. + + * jsc.pro: + +2009-10-23 Steve Block <steveblock@google.com> + + Reviewed by Dmitry Titov. + + Fixes a leak in createThreadInternal on Android. + https://bugs.webkit.org/show_bug.cgi?id=30698 + + * wtf/ThreadingPthreads.cpp: Modified. + (WTF::createThreadInternal): Avoid leaking a ThreadData object on failure. + +2009-10-22 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Alexey Proskuryakov. + + Fixed ASSERT when opening Safari's Caches window while the Web Inspector + is open. + + * runtime/Collector.cpp: + (JSC::typeName): Added two new types to the type name list in the Collector. + These types have been around for a while, but nobody remembered to consider them here. + + * runtime/JSCell.h: + (JSC::JSCell::isPropertyNameIterator): + * runtime/JSPropertyNameIterator.h: + (JSC::JSPropertyNameIterator::isPropertyNameIterator): Give the Collector + a way to tell if a cell is a JSPropertyNameIterator. + +2009-10-22 Steve Falkenburg <sfalken@apple.com> + + Reviewed by Jon Honeycutt. + + https://bugs.webkit.org/show_bug.cgi?id=30686 + Remove debug-specific def file. + Only Debug_All target uses JavaScriptCore_debug.dll naming, and since + that target is only used internally, maintaining two files just to + suppress a single link warning isn't worthwhile. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: Removed. + +2009-10-21 Jon Honeycutt <jhoneycutt@apple.com> + + <rdar://problem/7270320> Screenshots of off-screen plug-ins are blank + <rdar://problem/7270314> After halting a transparent PluginView on + Windows, the transparency is applied twice + + Reviewed by Dan Bernstein. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + Export WTF::deleteOwnedPtr(HDC). + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + Ditto. + +2009-10-20 Geoffrey Garen <ggaren@apple.com> + + Windows build fix: updated variable name. + + * runtime/DatePrototype.cpp: + (JSC::formatLocaleDate): + +2009-10-20 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Mark Rowe. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_next_pname): Slightly tweaked this #ifdef to match the + size of a JSValue because m_jsStrings is an array of JSValues. + +2009-10-20 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Mark Rowe. + + Fixed a 64-bit regression caused by the fix for + https://bugs.webkit.org/show_bug.cgi?id=30570. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_next_pname): Use TimesEight stepping on 64-bit, since + 64-bit pointers are eight bytes long. + +2009-10-20 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Refactored DateInstance::msToGregorianDateTime so that a DateInstance's + caller doesn't need to supply the DateInstance's own internal value to + the DateInstance. + + * runtime/DateInstance.cpp: + (JSC::DateInstance::getGregorianDateTime): Renamed from "msToGregorianDateTime". + + * runtime/DateInstance.h: + * runtime/DatePrototype.cpp: + (JSC::formatLocaleDate): + (JSC::dateProtoFuncToString): + (JSC::dateProtoFuncToUTCString): + (JSC::dateProtoFuncToISOString): + (JSC::dateProtoFuncToDateString): + (JSC::dateProtoFuncToTimeString): + (JSC::dateProtoFuncToLocaleString): + (JSC::dateProtoFuncToLocaleDateString): + (JSC::dateProtoFuncToLocaleTimeString): + (JSC::dateProtoFuncGetTime): + (JSC::dateProtoFuncGetFullYear): + (JSC::dateProtoFuncGetUTCFullYear): + (JSC::dateProtoFuncToGMTString): + (JSC::dateProtoFuncGetMonth): + (JSC::dateProtoFuncGetUTCMonth): + (JSC::dateProtoFuncGetDate): + (JSC::dateProtoFuncGetUTCDate): + (JSC::dateProtoFuncGetDay): + (JSC::dateProtoFuncGetUTCDay): + (JSC::dateProtoFuncGetHours): + (JSC::dateProtoFuncGetUTCHours): + (JSC::dateProtoFuncGetMinutes): + (JSC::dateProtoFuncGetUTCMinutes): + (JSC::dateProtoFuncGetSeconds): + (JSC::dateProtoFuncGetUTCSeconds): + (JSC::dateProtoFuncGetTimezoneOffset): + (JSC::setNewValueFromTimeArgs): + (JSC::setNewValueFromDateArgs): + (JSC::dateProtoFuncSetYear): + (JSC::dateProtoFuncGetYear): Also renamed "utc" to "outputIsUTC", for clarity. + +2009-10-20 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Geoffrey Garen. + + The op_next_pname should use 4 bytes addressing mode in case of JSValue32 + https://bugs.webkit.org/show_bug.cgi?id=30570 + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_next_pname): + +2009-10-20 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Oliver Hunt. + + Move OverridesMarkChildren flag from DatePrototype to its parent class + https://bugs.webkit.org/show_bug.cgi?id=30372 + + * runtime/DateInstance.h: + (JSC::DateInstance::createStructure): + * runtime/DatePrototype.h: + +2009-10-19 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Tightened up some put_by_id_transition code generation. + https://bugs.webkit.org/show_bug.cgi?id=30539 + + * jit/JIT.h: + * jit/JITPropertyAccess.cpp: + (JSC::JIT::testPrototype): + (JSC::JIT::privateCompilePutByIdTransition): No need to do object type + checks or read Structures and prototypes from objects: they're all known + constants at compile time. + +2009-10-19 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Added a private API for getting a global context from a context, for + clients who want to preserve a context for a later callback. + + * API/APICast.h: + (toGlobalRef): Added an ASSERT, since this function is used more often + than before. + + * API/JSContextRef.cpp: + * API/JSContextRefPrivate.h: Added. The new API. + + * API/tests/testapi.c: + (print_callAsFunction): + (main): Test the new API. + + * JavaScriptCore.exp: + * JavaScriptCore.xcodeproj/project.pbxproj: Build and export the new API. + +2009-10-17 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Tightened up some instanceof code generation. + https://bugs.webkit.org/show_bug.cgi?id=30488 + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_instanceof): + (JSC::JIT::emitSlow_op_instanceof): No need to do object type checks - + cell type checks and ImplementsDefaultHasIntance checks implicitly + supersede object type checks. + +2009-10-18 Kwang Yul Seo <skyul@company100.net> + + Reviewed by Darin Adler. + + Use _stricmp and _strnicmp instead of deprecated stricmp and strnicmp. + https://bugs.webkit.org/show_bug.cgi?id=30474 + + stricmp and strnicmp are deprecated beginning in Visual + C++ 2005. Use _stricmp and _strnicmp instead in StringExtras.h. + + * wtf/StringExtras.h: + (strncasecmp): + (strcasecmp): + +2009-10-16 Geoffrey Garen <ggaren@apple.com> + + Build fix: apparently we shouldn't export those symbols? + + * JavaScriptCore.exp: + +2009-10-16 Geoffrey Garen <ggaren@apple.com> + + Build fix: export some symbols. + + * JavaScriptCore.exp: + +2009-10-16 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + structure typeinfo flags should be inherited. + https://bugs.webkit.org/show_bug.cgi?id=30468 + + Add StructureFlag constant to the various JSC classes and use + it for the TypeInfo construction. This allows us to simply + accumulate flags by basing each classes StructureInfo on its parents. + + * API/JSCallbackConstructor.h: + (JSC::JSCallbackConstructor::createStructure): + * API/JSCallbackFunction.h: + (JSC::JSCallbackFunction::createStructure): + * API/JSCallbackObject.h: + (JSC::JSCallbackObject::createStructure): + * debugger/DebuggerActivation.h: + (JSC::DebuggerActivation::createStructure): + * runtime/Arguments.h: + (JSC::Arguments::createStructure): + * runtime/BooleanObject.h: + (JSC::BooleanObject::createStructure): + * runtime/DatePrototype.h: + (JSC::DatePrototype::createStructure): + * runtime/FunctionPrototype.h: + (JSC::FunctionPrototype::createStructure): + * runtime/GlobalEvalFunction.h: + (JSC::GlobalEvalFunction::createStructure): + * runtime/InternalFunction.h: + (JSC::InternalFunction::createStructure): + * runtime/JSActivation.h: + (JSC::JSActivation::createStructure): + * runtime/JSArray.h: + (JSC::JSArray::createStructure): + * runtime/JSByteArray.cpp: + (JSC::JSByteArray::createStructure): + * runtime/JSByteArray.h: + * runtime/JSFunction.h: + (JSC::JSFunction::createStructure): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::createStructure): + * runtime/JSNotAnObject.h: + (JSC::JSNotAnObject::createStructure): + * runtime/JSONObject.h: + (JSC::JSONObject::createStructure): + * runtime/JSObject.h: + (JSC::JSObject::createStructure): + * runtime/JSStaticScopeObject.h: + (JSC::JSStaticScopeObject::createStructure): + * runtime/JSVariableObject.h: + (JSC::JSVariableObject::createStructure): + * runtime/JSWrapperObject.h: + (JSC::JSWrapperObject::createStructure): + * runtime/MathObject.h: + (JSC::MathObject::createStructure): + * runtime/NumberConstructor.h: + (JSC::NumberConstructor::createStructure): + * runtime/NumberObject.h: + (JSC::NumberObject::createStructure): + * runtime/RegExpConstructor.h: + (JSC::RegExpConstructor::createStructure): + * runtime/RegExpObject.h: + (JSC::RegExpObject::createStructure): + * runtime/StringObject.h: + (JSC::StringObject::createStructure): + * runtime/StringObjectThatMasqueradesAsUndefined.h: + (JSC::StringObjectThatMasqueradesAsUndefined::createStructure): + +2009-10-16 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Fast for-in enumeration: Cache JSPropertyNameIterator; cache JSStrings + in JSPropertyNameIterator; inline more code. + + 1.024x as fast on SunSpider (fasta: 1.43x as fast). + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::dump): + * bytecode/Opcode.h: + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitGetPropertyNames): + (JSC::BytecodeGenerator::emitNextPropertyName): + * bytecompiler/BytecodeGenerator.h: Added a few extra operands to + op_get_pnames and op_next_pname so that we can track iteration state + in the register file instead of in the JSPropertyNameIterator. (To be + cacheable, the JSPropertyNameIterator must be stateless.) + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::tryCachePutByID): + (JSC::Interpreter::tryCacheGetByID): Updated for rename to + "normalizePrototypeChain" and removal of "isCacheable". + + (JSC::Interpreter::privateExecute): Updated for in-RegisterFile + iteration state tracking. + + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + * jit/JIT.h: + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_get_pnames): Updated for in-RegisterFile + iteration state tracking. + + (JSC::JIT::emit_op_next_pname): Inlined code generation for op_next_pname. + + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCachePutByID): + (JSC::JITThunks::tryCacheGetByID): Updated for rename to + "normalizePrototypeChain" and removal of "isCacheable". + + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + (JSC::): Added has_property and to_object stubs. Removed op_next_pname + stub, since has_property is all we need anymore. + + * parser/Nodes.cpp: + (JSC::ForInNode::emitBytecode): Updated for in-RegisterFile + iteration state tracking. + + * runtime/JSCell.h: + * runtime/JSObject.cpp: + (JSC::JSObject::getPropertyNames): Don't do caching at this layer + anymore, since we don't create a JSPropertyNameIterator at this layer. + + * runtime/JSPropertyNameIterator.cpp: + (JSC::JSPropertyNameIterator::create): Do do caching at this layer. + (JSC::JSPropertyNameIterator::get): Updated for in-RegisterFile + iteration state tracking. + (JSC::JSPropertyNameIterator::markChildren): Mark our JSStrings. + + * runtime/JSPropertyNameIterator.h: + (JSC::JSPropertyNameIterator::size): + (JSC::JSPropertyNameIterator::setCachedStructure): + (JSC::JSPropertyNameIterator::cachedStructure): + (JSC::JSPropertyNameIterator::setCachedPrototypeChain): + (JSC::JSPropertyNameIterator::cachedPrototypeChain): + (JSC::JSPropertyNameIterator::JSPropertyNameIterator): + (JSC::Structure::setEnumerationCache): Don't store iteration state in + a JSPropertyNameIterator. Do cache a JSPropertyNameIterator in a + Structure. + + * runtime/JSValue.h: + (JSC::asCell): + * runtime/MarkStack.h: Make those mischievous #include gods happy. + + * runtime/ObjectConstructor.cpp: + + * runtime/Operations.h: + (JSC::normalizePrototypeChain): Renamed countPrototypeChainEntriesAndCheckForProxies + to normalizePrototypeChain, since it changes dictionary prototypes to + non-dictionary objects. + + * runtime/PropertyNameArray.cpp: + (JSC::PropertyNameArray::add): + * runtime/PropertyNameArray.h: + (JSC::PropertyNameArrayData::PropertyNameArrayData): + (JSC::PropertyNameArray::data): + (JSC::PropertyNameArray::size): + (JSC::PropertyNameArray::begin): + (JSC::PropertyNameArray::end): Simplified some code here to help with + current and future refactoring. + + * runtime/Protect.h: + * runtime/Structure.cpp: + (JSC::Structure::~Structure): + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::removePropertyWithoutTransition): No need to clear + the enumeration cache with adding / removing properties without + transition. It is an error to add / remove properties without transition + once an object has been observed, and we can ASSERT to catch that. + + * runtime/Structure.h: + (JSC::Structure::enumerationCache): Changed the enumeration cache to + hold a JSPropertyNameIterator. + + * runtime/StructureChain.cpp: + * runtime/StructureChain.h: + (JSC::StructureChain::head): Removed StructureChain::isCacheable because + it was wrong-headed in two ways: (1) It gave up when a prototype was a + dictionary, but instead we want un-dictionary heavily accessed + prototypes; (2) It folded a test for hasDefaultGetPropertyNames() into + a generic test for "cacheable-ness", but hasDefaultGetPropertyNames() + is only releavant to for-in caching. + +2009-10-16 Steve Falkenburg <sfalken@apple.com> + + Reviewed by Adam Roben. + + Add a Debug_All configuration to build entire stack as debug. + Change Debug_Internal to: + - stop using _debug suffix for all WebKit/Safari binaries + - not use _debug as a DLL naming suffix + - use non-debug C runtime lib. + + * JavaScriptCore.vcproj/JavaScriptCore.make: Debug build in makefile should build Debug_All. + * JavaScriptCore.vcproj/JavaScriptCore.sln: Add Debug_All configuration. + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: Add Debug_All configuration. + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.vcproj: Renamed single configuration from "Release" to "all". + * JavaScriptCore.vcproj/JavaScriptCoreSubmit.sln: Add Debug_All configuration. + * JavaScriptCore.vcproj/WTF/WTF.vcproj: Add Debug_All configuration. + * JavaScriptCore.vcproj/jsc/jsc.vcproj: Add Debug_All configuration. + * JavaScriptCore.vcproj/testapi/testapi.vcproj: Add Debug_All configuration. + +2009-10-16 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Make typeinfo flags default to false + https://bugs.webkit.org/show_bug.cgi?id=30372 + + Last part -- replace HasDefaultGetPropertyNames with OverridesGetPropertyNames + flag. + + * API/JSCallbackConstructor.h: + (JSC::JSCallbackConstructor::createStructure): + * API/JSCallbackObject.h: + (JSC::JSCallbackObject::createStructure): + * debugger/DebuggerActivation.h: + (JSC::DebuggerActivation::createStructure): + * runtime/Arguments.h: + (JSC::Arguments::createStructure): + * runtime/BooleanObject.h: + (JSC::BooleanObject::createStructure): + * runtime/DatePrototype.h: + (JSC::DatePrototype::createStructure): + * runtime/FunctionPrototype.h: + (JSC::FunctionPrototype::createStructure): + * runtime/GlobalEvalFunction.h: + (JSC::GlobalEvalFunction::createStructure): + * runtime/JSAPIValueWrapper.h: + (JSC::JSAPIValueWrapper::createStructure): + * runtime/JSActivation.h: + (JSC::JSActivation::createStructure): + * runtime/JSArray.h: + (JSC::JSArray::createStructure): + * runtime/JSByteArray.cpp: + (JSC::JSByteArray::createStructure): + * runtime/JSFunction.h: + (JSC::JSFunction::createStructure): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::createStructure): + * runtime/JSNotAnObject.h: + (JSC::JSNotAnObject::createStructure): + * runtime/JSONObject.h: + (JSC::JSONObject::createStructure): + * runtime/JSObject.cpp: + (JSC::JSObject::getPropertyNames): + * runtime/JSObject.h: + (JSC::JSObject::createStructure): + * runtime/JSStaticScopeObject.h: + (JSC::JSStaticScopeObject::createStructure): + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::overridesGetPropertyNames): + * runtime/JSVariableObject.h: + (JSC::JSVariableObject::createStructure): + * runtime/JSWrapperObject.h: + (JSC::JSWrapperObject::createStructure): + * runtime/MathObject.h: + (JSC::MathObject::createStructure): + * runtime/NumberConstructor.h: + (JSC::NumberConstructor::createStructure): + * runtime/NumberObject.h: + (JSC::NumberObject::createStructure): + * runtime/RegExpConstructor.h: + (JSC::RegExpConstructor::createStructure): + * runtime/RegExpObject.h: + (JSC::RegExpObject::createStructure): + * runtime/StringObject.h: + (JSC::StringObject::createStructure): + * runtime/StringObjectThatMasqueradesAsUndefined.h: + (JSC::StringObjectThatMasqueradesAsUndefined::createStructure): + * runtime/StructureChain.cpp: + (JSC::StructureChain::isCacheable): + +2009-10-16 Kevin Ollivier <kevino@theolliviers.com> + + wxMSW build fix, we can't use the simple hash there because the PlatformModuleVersion + structure differs. + + * wtf/Platform.h: + +2009-10-16 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Simon Hausmann. + + [Qt] Implement ExecutableAllocator for Symbian + https://bugs.webkit.org/show_bug.cgi?id=29946 + + Tested with YARR JIT enabled for Symbian; + This patch does not (yet) enable YARR JIT by default. + + * JavaScriptCore.pri: + * jit/ExecutableAllocator.h: + * jit/ExecutableAllocatorSymbian.cpp: Added. + (JSC::ExecutableAllocator::intializePageSize): + (JSC::ExecutablePool::systemAlloc): + (JSC::ExecutablePool::systemRelease): + +2009-10-15 Oliver Hunt <oliver@apple.com> + + Reviewed by Darin Adler. + + Make typeinfo flags default to false + https://bugs.webkit.org/show_bug.cgi?id=30372 + + Part 2 -- Reverse the TypeInfo HasDefaultMark flag to OverridesMarkChildren, etc + + * API/JSCallbackConstructor.h: + (JSC::JSCallbackConstructor::createStructure): + * API/JSCallbackFunction.h: + (JSC::JSCallbackFunction::createStructure): + * API/JSCallbackObject.h: + (JSC::JSCallbackObject::createStructure): + * debugger/DebuggerActivation.h: + (JSC::DebuggerActivation::createStructure): + * runtime/Arguments.h: + (JSC::Arguments::createStructure): + * runtime/BooleanObject.h: + (JSC::BooleanObject::createStructure): + * runtime/DatePrototype.h: + (JSC::DatePrototype::createStructure): + * runtime/FunctionPrototype.h: + (JSC::FunctionPrototype::createStructure): + * runtime/GetterSetter.h: + (JSC::GetterSetter::createStructure): + * runtime/GlobalEvalFunction.h: + (JSC::GlobalEvalFunction::createStructure): + * runtime/InternalFunction.h: + (JSC::InternalFunction::createStructure): + * runtime/JSAPIValueWrapper.h: + (JSC::JSAPIValueWrapper::createStructure): + * runtime/JSActivation.h: + (JSC::JSActivation::createStructure): + * runtime/JSArray.h: + (JSC::JSArray::createStructure): + (JSC::MarkStack::markChildren): + * runtime/JSByteArray.cpp: + (JSC::JSByteArray::createStructure): + * runtime/JSFunction.h: + (JSC::JSFunction::createStructure): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::createStructure): + * runtime/JSNotAnObject.h: + (JSC::JSNotAnObject::createStructure): + * runtime/JSNumberCell.h: + (JSC::JSNumberCell::createStructure): + * runtime/JSONObject.h: + (JSC::JSONObject::createStructure): + * runtime/JSObject.h: + (JSC::JSObject::createStructure): + * runtime/JSPropertyNameIterator.h: + (JSC::JSPropertyNameIterator::createStructure): + * runtime/JSStaticScopeObject.h: + (JSC::JSStaticScopeObject::createStructure): + * runtime/JSString.h: + (JSC::JSString::createStructure): + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::overridesMarkChildren): + * runtime/JSVariableObject.h: + (JSC::JSVariableObject::createStructure): + * runtime/JSWrapperObject.h: + (JSC::JSWrapperObject::createStructure): + * runtime/MathObject.h: + (JSC::MathObject::createStructure): + * runtime/NumberConstructor.h: + (JSC::NumberConstructor::createStructure): + * runtime/NumberObject.h: + (JSC::NumberObject::createStructure): + * runtime/RegExpConstructor.h: + (JSC::RegExpConstructor::createStructure): + * runtime/RegExpObject.h: + (JSC::RegExpObject::createStructure): + * runtime/StringObject.h: + (JSC::StringObject::createStructure): + * runtime/StringObjectThatMasqueradesAsUndefined.h: + (JSC::StringObjectThatMasqueradesAsUndefined::createStructure): + +2009-10-14 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Make typeinfo flags default to false + https://bugs.webkit.org/show_bug.cgi?id=30372 + + Part 1. Reverse the HasStandardGetOwnPropertySlot flag. + + * API/JSCallbackConstructor.h: + (JSC::JSCallbackConstructor::createStructure): + * API/JSCallbackFunction.h: + (JSC::JSCallbackFunction::createStructure): + * API/JSCallbackObject.h: + (JSC::JSCallbackObject::createStructure): + * debugger/DebuggerActivation.h: + (JSC::DebuggerActivation::createStructure): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * runtime/Arguments.h: + (JSC::Arguments::createStructure): + * runtime/BooleanObject.h: + (JSC::BooleanObject::createStructure): + * runtime/DatePrototype.h: + (JSC::DatePrototype::createStructure): + * runtime/FunctionPrototype.h: + (JSC::FunctionPrototype::createStructure): + * runtime/GlobalEvalFunction.h: + (JSC::GlobalEvalFunction::createStructure): + * runtime/InternalFunction.h: + (JSC::InternalFunction::createStructure): + * runtime/JSActivation.h: + (JSC::JSActivation::createStructure): + * runtime/JSArray.h: + (JSC::JSArray::createStructure): + * runtime/JSByteArray.cpp: + (JSC::JSByteArray::createStructure): + * runtime/JSFunction.h: + (JSC::JSFunction::createStructure): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::createStructure): + * runtime/JSNumberCell.h: + (JSC::JSNumberCell::createStructure): + * runtime/JSONObject.h: + (JSC::JSONObject::createStructure): + * runtime/JSObject.h: + (JSC::JSObject::createStructure): + (JSC::JSCell::fastGetOwnPropertySlot): + * runtime/JSStaticScopeObject.h: + (JSC::JSStaticScopeObject::createStructure): + * runtime/JSString.h: + (JSC::JSString::createStructure): + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::overridesGetOwnPropertySlot): + * runtime/JSVariableObject.h: + (JSC::JSVariableObject::createStructure): + * runtime/JSWrapperObject.h: + (JSC::JSWrapperObject::createStructure): + * runtime/MathObject.h: + (JSC::MathObject::createStructure): + * runtime/NumberConstructor.h: + (JSC::NumberConstructor::createStructure): + * runtime/NumberObject.h: + (JSC::NumberObject::createStructure): + * runtime/RegExpConstructor.h: + (JSC::RegExpConstructor::createStructure): + * runtime/RegExpObject.h: + (JSC::RegExpObject::createStructure): + * runtime/StringObject.h: + (JSC::StringObject::createStructure): + * runtime/StringObjectThatMasqueradesAsUndefined.h: + (JSC::StringObjectThatMasqueradesAsUndefined::createStructure): + +2009-10-14 Kevin Ollivier <kevino@theolliviers.com> +2009-10-14 Darin Adler <darin@apple.com> + + Additions so fix for https://bugs.webkit.org/show_bug.cgi?id=18994 + can build on Windows. + + * wtf/MathExtras.h: Added llround and llroundf for Windows. + +2009-10-14 Kevin Ollivier <kevino@theolliviers.com> + + wx build fix. Set ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH for plugins while we're still building stubs. + + * wtf/Platform.h: + +2009-10-13 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Simon Hausmann. + + Refactor ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH + https://bugs.webkit.org/show_bug.cgi?id=30278 + + Move the definition of ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH + from the make system into common code. + + * wtf/Platform.h: + +2009-10-13 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Darin Adler. + + ARM compiler does not understand reinterpret_cast<void*> + https://bugs.webkit.org/show_bug.cgi?id=29034 + + Change reinterpret_cast<void*> to regular C style (void*) cast + for the ARM RVCT compiler. + + * assembler/MacroAssemblerCodeRef.h: + (JSC::FunctionPtr::FunctionPtr): + * jit/JITOpcodes.cpp: Cast to FunctionPtr first + instead of directly casting to reinterpret_cast + * jit/JITStubCall.h: Ditto + change the type of m_stub + from void* to FunctionPtr. + (JSC::JITStubCall::JITStubCall): + (JSC::JITStubCall::call): + * jit/JITStubs.cpp: Ditto. + (JSC::DEFINE_STUB_FUNCTION(EncodedJSValue, op_throw)): + +2009-10-11 Oliver Hunt <oliver@apple.com> + + Re-enable the JIT. + + * wtf/Platform.h: + +2009-10-10 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Support for String.trim(), String.trimLeft() and String.trimRight() methods + https://bugs.webkit.org/show_bug.cgi?id=26590 + + Implement trim, trimLeft, and trimRight + + * runtime/StringPrototype.cpp: + (JSC::isTrimWhitespace): + Our normal string whitespace function does not include U+200B which + is needed for compatibility with mozilla's implementation of trim. + U+200B does not appear to be expected according to spec, however I am + choosing to be lax, and match mozilla behavior so have added this + exception. + (JSC::trimString): + +2009-10-09 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Eliminated some legacy bytecode weirdness. + + Use vPC[x] subscripting instead of ++vPC to access instruction operands. + This is simpler, and often more efficient. + + To support this, and to remove use of hard-coded offsets in bytecode and + JIT code generation and dumping, calculate jump offsets from the beginning + of an instruction, rather than the middle or end. + + Also, use OPCODE_LENGTH instead of hard-coded constants for the sizes of + opcodes. + + SunSpider reports no change in JIT mode, and a 1.01x speedup in Interpreter + mode. + + * bytecode/CodeBlock.cpp: + (JSC::printConditionalJump): + (JSC::CodeBlock::dump): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitJump): + (JSC::BytecodeGenerator::emitJumpIfTrue): + (JSC::BytecodeGenerator::emitJumpIfFalse): + (JSC::BytecodeGenerator::emitJumpIfNotFunctionCall): + (JSC::BytecodeGenerator::emitJumpIfNotFunctionApply): + (JSC::BytecodeGenerator::emitComplexJumpScopes): + (JSC::BytecodeGenerator::emitJumpScopes): + (JSC::BytecodeGenerator::emitNextPropertyName): + (JSC::BytecodeGenerator::emitCatch): + (JSC::BytecodeGenerator::emitJumpSubroutine): + (JSC::prepareJumpTableForImmediateSwitch): + (JSC::prepareJumpTableForCharacterSwitch): + (JSC::prepareJumpTableForStringSwitch): + (JSC::BytecodeGenerator::endSwitch): + * bytecompiler/Label.h: + (JSC::Label::setLocation): + (JSC::Label::bind): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::resolve): + (JSC::Interpreter::resolveSkip): + (JSC::Interpreter::resolveGlobal): + (JSC::Interpreter::resolveBase): + (JSC::Interpreter::resolveBaseAndProperty): + (JSC::Interpreter::createExceptionScope): + (JSC::Interpreter::privateExecute): + * interpreter/Interpreter.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_jnless): + (JSC::JIT::emitSlow_op_jnless): + (JSC::JIT::emit_op_jnlesseq): + (JSC::JIT::emitSlow_op_jnlesseq): + (JSC::JIT::emitBinaryDoubleOp): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_jmp): + (JSC::JIT::emit_op_loop): + (JSC::JIT::emit_op_loop_if_less): + (JSC::JIT::emitSlow_op_loop_if_less): + (JSC::JIT::emit_op_loop_if_lesseq): + (JSC::JIT::emitSlow_op_loop_if_lesseq): + (JSC::JIT::emit_op_loop_if_true): + (JSC::JIT::emitSlow_op_loop_if_true): + (JSC::JIT::emit_op_jfalse): + (JSC::JIT::emitSlow_op_jfalse): + (JSC::JIT::emit_op_jtrue): + (JSC::JIT::emitSlow_op_jtrue): + (JSC::JIT::emit_op_jeq_null): + (JSC::JIT::emit_op_jneq_null): + (JSC::JIT::emit_op_jneq_ptr): + (JSC::JIT::emit_op_jsr): + (JSC::JIT::emit_op_next_pname): + (JSC::JIT::emit_op_jmp_scopes): + +2009-10-09 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Migrated some code that didn't belong out of Structure. + + SunSpider says maybe 1.03x faster. + + * runtime/JSCell.h: Nixed Structure::markAggregate, and made marking of + a Structure's prototype the direct responsility of the object using it. + (Giving Structure a mark function was misleading because it implied that + all live structures get marked during GC, when they don't.) + + * runtime/JSGlobalObject.cpp: + (JSC::markIfNeeded): + (JSC::JSGlobalObject::markChildren): Added code to mark prototypes stored + on the global object. Maybe this wasn't necessary, but now we don't have + to wonder. + + * runtime/JSObject.cpp: + (JSC::JSObject::getPropertyNames): + (JSC::JSObject::getOwnPropertyNames): + (JSC::JSObject::getEnumerableNamesFromClassInfoTable): + * runtime/JSObject.h: + (JSC::JSObject::markChildrenDirect): + * runtime/PropertyNameArray.h: + * runtime/Structure.cpp: + * runtime/Structure.h: + (JSC::Structure::setEnumerationCache): + (JSC::Structure::enumerationCache): Moved property name gathering code + from Structure to JSObject because having a Structure iterate its JSObject + was a layering violation. A JSObject is implemented using a Structure; not + the other way around. + +2009-10-09 Mark Rowe <mrowe@apple.com> + + Attempt to fix the GTK release build. + + * GNUmakefile.am: Include Grammar.cpp in release builds now that + AllInOneFile.cpp is gone. + +2009-10-09 Gabor Loki <loki@inf.u-szeged.hu> + + Rubber-stamped by Eric Seidel. + + Add ARM JIT support for Gtk port (disabled by default) + https://bugs.webkit.org/show_bug.cgi?id=30228 + + * GNUmakefile.am: + +2009-10-08 Geoffrey Garen <ggaren@apple.com> + + Tiger build fix: added a few more variable initializations. + + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncReplace): + (JSC::stringProtoFuncSearch): + +2009-10-08 Geoffrey Garen <ggaren@apple.com> + + Qt build fix: added missing #include. + + * jsc.cpp: + +2009-10-08 Geoffrey Garen <ggaren@apple.com> + + Tiger build fix: initialize variable whose initialization the compiler + can't otherwise figure out. + + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::match): + +2009-10-08 Geoffrey Garen <ggaren@apple.com> + + Windows build fix: updated exports. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-10-08 Geoffrey Garen <ggaren@apple.com> + + Tiger build fix: fixed file name case. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2009-10-08 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Maciej Stachowiak. + + At long last, I pronounce the death of AllInOneFile.cpp. + + SunSpider reports a 1.01x speedup. + + * AllInOneFile.cpp: Removed. + * GNUmakefile.am: + * JavaScriptCore.exp: + * JavaScriptCore.gypi: + * JavaScriptCore.xcodeproj/project.pbxproj: Added missing project files + to compilation stages. + + * parser/Grammar.y: + * parser/Lexer.cpp: + * parser/Lexer.h: + (JSC::jscyylex): + * runtime/ArrayConstructor.cpp: + (JSC::constructArrayWithSizeQuirk): + * runtime/Collector.h: + * runtime/JSCell.cpp: + (JSC::JSCell::operator new): + * runtime/JSCell.h: + (JSC::JSCell::operator new): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::operator new): + * runtime/JSNumberCell.h: + (JSC::JSNumberCell::operator new): + * runtime/JSString.cpp: + * runtime/JSString.h: + (JSC::jsString): + (JSC::jsSubstring): + (JSC::jsOwnedString): + * runtime/RegExpConstructor.cpp: + * runtime/RegExpConstructor.h: + (JSC::RegExpConstructorPrivate::RegExpConstructorPrivate): + (JSC::RegExpConstructorPrivate::lastOvector): + (JSC::RegExpConstructorPrivate::tempOvector): + (JSC::RegExpConstructorPrivate::changeLastOvector): + (JSC::RegExpConstructor::performMatch): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncMatch): + * yarr/RegexJIT.cpp: + * yarr/RegexJIT.h: + (JSC::Yarr::executeRegex): Inlined a few things that Shark said + were hot, on the presumption that AllInOneFile.cpp used to inline them + automatically. + +2009-10-08 Zoltan Herczeg <zherczeg@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Fix for JIT'ed op_call instructions (evals, constructs, etc.) + when !ENABLE(JIT_OPTIMIZE_CALL) && USE(JSVALUE32_64) + + https://bugs.webkit.org/show_bug.cgi?id=30201 + + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + +2009-10-07 Geoffrey Garen <ggaren@apple.com> + + Windows build fix: removed no longer exported symbol. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-10-07 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Fixed <rdar://problem/5751979> Database code takes JSLock on secondary + thread, permanently slowing down JavaScript + + Removed the optional lock from Heap::protect, Heap::unprotect, and friends, + since WebCore no longer uses it. + + * JavaScriptCore.exp: + * runtime/Collector.cpp: + (JSC::Heap::protect): + (JSC::Heap::unprotect): + (JSC::Heap::markProtectedObjects): + (JSC::Heap::protectedGlobalObjectCount): + (JSC::Heap::protectedObjectCount): + (JSC::Heap::protectedObjectTypeCounts): + * runtime/Collector.h: + +2009-10-07 Zoltan Horvath <zoltan@webkit.org> + + Reviewed by Darin Adler. + + Allow custom memory allocation control for JavaScriptCore's IdentifierArena + https://bugs.webkit.org/show_bug.cgi?id=30158 + + Inherits IdentifierArena class from FastAllocBase because it has been + instantiated by 'new' in JavaScriptCore/parser/ParserArena.cpp:36. + + * parser/ParserArena.h: + +2009-10-07 Adam Roben <aroben@apple.com> + + Export DateInstance::info in a way that works on Windows + + Fixes <http://webkit.org/b/30171> + fast/dom/Window/window-postmessage-clone.html fails on Windows + + Reviewed by Anders Carlsson. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + Removed the export of DateInstance::info from here. + + * runtime/DateInstance.h: Use JS_EXPORTDATA to export + DateInstance::info, which is the required way of exporting data on + Windows. + +2009-10-07 Jørgen Lind <jorgen.lind@nokia.com> + + Reviewed by Simon Hausmann. + + When enabling or disabling the JIT through .qmake.cache, make sure + to also toggle ENABLE_YARR_JIT. + + * JavaScriptCore.pri: + +2009-10-06 Priit Laes <plaes@plaes.org> + + Reviewed by Gavin Barraclough. + + Linking fails with "relocation R_X86_64_PC32 against symbol + `cti_vm_throw'" + https://bugs.webkit.org/show_bug.cgi?id=28422 + + * jit/JITStubs.cpp: + Mark cti_vm_throw symbol as PLT-indirect symbol, so it doesn't end up + in text segment causing relocation errors on amd64 architecture. + Introduced new define SYMBOL_STRING_RELOCATION for such symbols. + +2009-10-06 Oliver Hunt <oliver@apple.com> + + Windows linking fix + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-10-06 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (build fix). + + Windows build fix. + + * runtime/DateInstance.cpp: + +2009-10-05 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + It should be possible to post (clone) built-in JS objects to Workers + https://bugs.webkit.org/show_bug.cgi?id=22878 + + Expose helpers to throw correct exceptions during object graph walk + used for cloning and add a helper function to create Date instances + without going through the JS Date constructor function. + + * JavaScriptCore.exp: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/DateInstance.cpp: + (JSC::DateInstance::DateInstance): + * runtime/DateInstance.h: + * runtime/ExceptionHelpers.cpp: + (JSC::createTypeError): + * runtime/ExceptionHelpers.h: + +2009-10-06 David Levin <levin@chromium.org> + + Reviewed by Oliver Hunt. + + StringImpl needs a method to get an instance for another thread which doesn't copy the underlying buffer. + https://bugs.webkit.org/show_bug.cgi?id=30095 + + * wtf/CrossThreadRefCounted.h: + Removed an unused function and assert improvement. + (WTF::CrossThreadRefCounted::isOwnedByCurrentThread): Moved out common code from asserts. + (WTF::CrossThreadRefCounted::ref): Changed assert to use the common method. + (WTF::CrossThreadRefCounted::deref): Changed assert to use the common method. + (WTF::CrossThreadRefCounted::crossThreadCopy): Since this includes a potentially + non-threadsafe operation, add an assert that the class is owned by the current thread. + +2009-10-05 Kevin Ollivier <kevino@theolliviers.com> + + wx build fix. Add Symbian files to the list of excludes. + + * wscript: + +2009-10-05 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> + + Reviewed by Simon Hausmann. + + [Qt] Remove precompiled header from JavaScriptCore compilation to + prevent qmake warning during autonomous compilation. + https://bugs.webkit.org/show_bug.cgi?id=30069 + + * JavaScriptCore.pro: + +2009-10-02 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Removed the concept of a "fast access cutoff" in arrays, because it + punished some patterns of array access too much, and made things too + complex for inlining in some cases. + + 1.3% speedup on SunSpider. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emitSlow_op_put_by_val): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_get_by_val): + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emit_op_put_by_val): + (JSC::JIT::emitSlow_op_put_by_val): + * jit/JITStubs.cpp: + * jit/JITStubs.h: + (JSC::): Check m_vectorLength instead of m_fastAccessCutoff when + getting / putting from / to an array. Inline putting past the end of + the array. + + * runtime/JSArray.cpp: + (JSC::JSArray::JSArray): + (JSC::JSArray::getOwnPropertySlot): + (JSC::JSArray::getOwnPropertyDescriptor): + (JSC::JSArray::put): + (JSC::JSArray::putSlowCase): + (JSC::JSArray::deleteProperty): + (JSC::JSArray::getOwnPropertyNames): + (JSC::JSArray::increaseVectorLength): + (JSC::JSArray::setLength): + (JSC::JSArray::pop): + (JSC::JSArray::push): + (JSC::JSArray::sort): + (JSC::JSArray::fillArgList): + (JSC::JSArray::copyToRegisters): + (JSC::JSArray::compactForSorting): + (JSC::JSArray::checkConsistency): + * runtime/JSArray.h: + (JSC::JSArray::canGetIndex): + (JSC::JSArray::canSetIndex): + (JSC::JSArray::setIndex): + (JSC::JSArray::markChildrenDirect): Removed m_fastAccessCutoff, and + replaced with checks for JSValue() to detect reads and writes from / to + uninitialized parts of the array. + +2009-10-02 Jonni Rainisto <jonni.rainisto@nokia.com> + + Reviewed by Darin Adler. + + Math.random() gives too low values on Win32 when _CRT_RAND_S is not defined + https://bugs.webkit.org/show_bug.cgi?id=29956 + + * wtf/RandomNumber.cpp: + (WTF::randomNumber): Added PLATFORM(WIN_OS) to handle 15bit rand() + +2009-10-02 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Take one branch instead of two to test for JSValue(). + + 1.1% SunSpider speedup. + + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_to_jsnumber): + (JSC::JIT::emit_op_create_arguments): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emitSlow_op_get_by_val): + (JSC::JIT::emit_op_put_by_val): Test for the empty value tag, instead + of testing for the cell tag with a 0 payload. + + * runtime/JSValue.cpp: + (JSC::JSValue::description): Added support for dumping the new empty value, + and deleted values, in debug builds. + + * runtime/JSValue.h: + (JSC::JSValue::JSValue()): Construct JSValue() with the empty value tag. + + (JSC::JSValue::JSValue(JSCell*)): Convert null pointer to the empty value + tag, to avoid having two different c++ versions of null / empty. + + (JSC::JSValue::operator bool): Test for the empty value tag, instead + of testing for the cell tag with a 0 payload. + +2009-10-02 Steve Falkenburg <sfalken@apple.com> + + Reviewed by Mark Rowe. + + <https://bugs.webkit.org/show_bug.cgi?id=29989> + Safari version number shouldn't be exposed in WebKit code + + For a WebKit version of 532.3.4: + Product version is: 5.32.3.4 (was 4.0.3.0) + File version is: 5.32.3.4 (was 4.532.3.4) + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.rc: + +2009-10-02 Tor Arne Vestbø <tor.arne.vestbo@nokia.com> + + Rubber-stamped by Simon Hausmann. + + Fix the Qt on Mac OS X build. + + * wtf/FastMalloc.cpp: + +2009-10-02 Jørgen Lind <jorgen.lind@nokia.com> + + Reviewed by Simon Hausmann. + + Allow enabling and disabling of the JIT through a qmake variable. + + Qt's configure may set this variable through .qmake.cache if a + commandline option is given and/or the compile test for hwcap.h + failed/succeeded. + + * JavaScriptCore.pri: + +2009-10-01 Mark Rowe <mrowe@apple.com> + + Fix the Tiger build. Don't unconditionally enable 3D canvas as it is not supported on Tiger. + + * Configurations/FeatureDefines.xcconfig: + +2009-10-01 Yongjun Zhang <yongjun.zhang@nokia.com> + + Reviewed by Darin Adler. + + https://bugs.webkit.org/show_bug.cgi?id=29187 + + Don't inline ~ListRefPtr() to work around winscw compiler forward declaration + bug regarding templated classes. + + The compiler bug is reported at: + https://xdabug001.ext.nokia.com/bugzilla/show_bug.cgi?id=9812 + + The change will be reverted when the above bug is fixed in winscw compiler. + + * wtf/ListRefPtr.h: + (WTF::::~ListRefPtr): + +2009-10-01 Zoltan Horvath <zoltan@webkit.org> + + Reviewed by Simon Hausmann. + + [Qt] Allow custom memory allocation control for the whole JavaScriptCore + https://bugs.webkit.org/show_bug.cgi?id=27029 + + Since in JavaScriptCore almost every class which has been instantiated by operator new is + inherited from FastAllocBase (bug #20422), we disable customizing global operator new for the Qt-port + when USE_SYSTEM_MALLOC=0. + + Add #include <unistd.h> to FastMalloc.cpp because it's used by TCMalloc_PageHeap::scavengerThread(). + (It's needed for the functionality of TCmalloc.) + + Add TCSystemAlloc.cpp to JavaScriptCore.pri if USE_SYSTEM_MALLOC is disabled. + + * JavaScriptCore.pri: + * wtf/FastMalloc.cpp: + (WTF::sleep): + * wtf/FastMalloc.h: + +2009-09-30 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by George Staikos. + + Defines two pseudo-platforms for ARM and Thumb-2 instruction set. + https://bugs.webkit.org/show_bug.cgi?id=29122 + + Introduces WTF_PLATFORM_ARM_TRADITIONAL and WTF_PLATFORM_ARM_THUMB2 + macros on ARM platforms. The PLATFORM(ARM_THUMB2) should be used + when Thumb-2 instruction set is the required target. The + PLATFORM(ARM_TRADITIONAL) is for generic ARM instruction set. In + case where the code is common the PLATFORM(ARM) have to be used. + + Modified by George Wright <gwright@rim.com> to correctly work + with the RVCT-defined __TARGET_ARCH_ARM and __TARGET_ARCH_THUMB + compiler macros, as well as adding readability changes. + + * wtf/Platform.h: + +2009-09-30 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Devirtualise array toString conversion + + Tweak the implementation of Array.prototype.toString to have a fast path + when acting on a true JSArray. + + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncToString): + +2009-09-30 Csaba Osztrogonac <oszi@inf.u-szeged.hu> + + Reviewed by Geoffrey Garen. + + Buildfix for platforms using JSVALUE32. + https://bugs.webkit.org/show_bug.cgi?id=29915 + + After http://trac.webkit.org/changeset/48905 the build broke in JSVALUE32 case. + Also removed unreachable code. + + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_add): + - Declaration of "OperandTypes types" moved before first use. + - Typos fixed: dst modified to result, regT2 added. + - Unreachable code removed. + (JSC::JIT::emitSlow_op_add): + - Missing declaration of "OperandTypes types" added. + +2009-09-30 Janne Koskinen <janne.p.koskinen@digia.com> + + Reviewed by Simon Hausmann. + + Reduce heap size on Symbian from 64MB to 8MB. + + This is not a perfect fix, it requires more fine tuning. + But this makes it possible again to debug in the emulator, + which is more important in order to be able to fix other + run-time issues. + + * runtime/Collector.h: + +2009-09-30 Janne Koskinen <janne.p.koskinen@digia.com> + + Reviewed by Simon Hausmann. + + Fix CRASH() macro for Symbian build. + + * wtf/Assertions.h: Added missing } + +2009-09-29 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Gavin Barraclough. + + Inlined a few math operations. + + ~1% SunSpider speedup. + + * jit/JIT.h: + * jit/JITArithmetic.cpp: + (JSC::JIT::compileBinaryArithOpSlowCase): + (JSC::JIT::emitSlow_op_add): + (JSC::JIT::emitSlow_op_mul): + (JSC::JIT::emit_op_sub): + (JSC::JIT::emitSlow_op_sub): Don't take a stub call when operating on + a constant int and a double. + +2009-09-28 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Tidy up codeblock sampler + https://bugs.webkit.org/show_bug.cgi?id=29836 + + Some rather simple refactoring of codeblock sampler so that + it's easier for us to use it to find problems in non-jsc + environments + + * JavaScriptCore.exp: + * bytecode/SamplingTool.h: + * debugger/Debugger.cpp: + (JSC::evaluateInGlobalCallFrame): + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::evaluate): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::Interpreter): + (JSC::Interpreter::execute): + (JSC::Interpreter::privateExecute): + (JSC::Interpreter::enableSampler): + (JSC::Interpreter::dumpSampleData): + (JSC::Interpreter::startSampling): + (JSC::Interpreter::stopSampling): + * interpreter/Interpreter.h: + (JSC::Interpreter::sampler): + * jit/JIT.h: + * jsc.cpp: + (runWithScripts): + * runtime/Completion.cpp: + (JSC::checkSyntax): + (JSC::evaluate): + * runtime/Executable.h: + (JSC::EvalExecutable::EvalExecutable): + (JSC::ProgramExecutable::create): + (JSC::ProgramExecutable::ProgramExecutable): + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::startSampling): + (JSC::JSGlobalData::stopSampling): + (JSC::JSGlobalData::dumpSampleData): + * runtime/JSGlobalData.h: + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncEval): + +2009-09-29 Jeremy Orlow <jorlow@chromium.org> + + Reviewed by Dimitri Glazkov. + + Add GYP generated files to svn:ignore + https://bugs.webkit.org/show_bug.cgi?id=29895 + + The following files are generated by JavaScriptCore's GYP file and should be ignored: + + pcre.mk + wtf.scons + wtf.mk + SConstruct + wtf_config.scons + wtf_config.mk + pcre.scons + + * JavaScriptCore.gyp: Changed property svn:ignore. + +2009-09-29 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Standardized an optimization for adding non-numbers. + + SunSpider says maybe a tiny speedup. + + * jit/JITArithmetic.cpp: + (JSC::JIT::emit_op_add): + (JSC::JIT::emitSlow_op_add): + +2009-09-29 Geoffrey Garen <ggaren@apple.com> + + Windows build fix: export a new symbol. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-28 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Removed virtual destructor from JSGlobalObjectData to eliminate pointer + fix-ups when accessing JSGlobalObject::d. + + Replaced with an explicit destructor function pointer. + + 6% speedup on bench-alloc-nonretained.js. + + * JavaScriptCore.exp: + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::~JSGlobalObject): + (JSC::JSGlobalObject::destroyJSGlobalObjectData): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::JSGlobalObjectData::JSGlobalObjectData): + (JSC::JSGlobalObject::JSGlobalObject): + +2009-09-29 Janne Koskinen <janne.p.koskinen@digia.com> + + Reviewed by David Kilzer. + + [Qt] Assert messages prints visible in Symbian + https://bugs.webkit.org/show_bug.cgi?id=29808 + + Asserts use vprintf to print the messages to stderr. + In Symbian Open C it is not possible to see stderr so + I routed the messages to stdout instead. + + * wtf/Assertions.cpp: + +2009-09-29 Janne Koskinen <janne.p.koskinen@digia.com> + + Reviewed by Darin Adler. + + [Qt] Symbian CRASH macro implementation + + Added Symbian specific crash macro that + stops to crash line if JIT debugging is used. + Additional differentiation of access violation + (KERN-EXEC 3) and CRASH panic. + + * wtf/Assertions.h: + +2009-09-28 Mark Rowe <mrowe@apple.com> + + Fix the PowerPC build. + + * JavaScriptCore.exp: + +2009-09-28 Mark Rowe <mrowe@apple.com> + + Reviewed by Gavin Barraclough. + + <rdar://problem/7195704> JavaScriptCore fails to mark registers when built for x86_64 using LLVM GCC. + + * runtime/Collector.cpp: + (JSC::Heap::markCurrentThreadConservatively): Force jmp_buf to use the appropriate alignment for a pointer + to ensure that we correctly interpret the contents of registers during marking. + +2009-09-28 Geoffrey Garen <ggaren@apple.com> + + Windows build fix: added new exports. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-28 Geoffrey Garen <ggaren@apple.com> + + Windows build fix: removed exports that no longer exist. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-28 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Darin Adler. + + NotNullPassRefPtr: smart pointer optimized for passing references that are not null + https://bugs.webkit.org/show_bug.cgi?id=29822 + + Added NotNullPassRefPtr, and deployed it in all places that initialize + JavaScript objects. + + 2.2% speedup on bench-allocate-nonretained.js. + + * API/JSCallbackConstructor.cpp: + (JSC::JSCallbackConstructor::JSCallbackConstructor): + * API/JSCallbackConstructor.h: + * API/JSCallbackObject.h: + * API/JSCallbackObjectFunctions.h: + (JSC::JSCallbackObject::JSCallbackObject): + * JavaScriptCore.exp: + * bytecode/CodeBlock.h: + (JSC::CodeBlock::addFunctionDecl): + (JSC::CodeBlock::addFunctionExpr): + * runtime/ArrayConstructor.cpp: + (JSC::ArrayConstructor::ArrayConstructor): + * runtime/ArrayConstructor.h: + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::ArrayPrototype): + * runtime/ArrayPrototype.h: + * runtime/BooleanConstructor.cpp: + (JSC::BooleanConstructor::BooleanConstructor): + * runtime/BooleanConstructor.h: + * runtime/BooleanObject.cpp: + (JSC::BooleanObject::BooleanObject): + * runtime/BooleanObject.h: + * runtime/BooleanPrototype.cpp: + (JSC::BooleanPrototype::BooleanPrototype): + * runtime/BooleanPrototype.h: + * runtime/DateConstructor.cpp: + (JSC::DateConstructor::DateConstructor): + * runtime/DateConstructor.h: + * runtime/DateInstance.cpp: + (JSC::DateInstance::DateInstance): + * runtime/DateInstance.h: + * runtime/DatePrototype.cpp: + (JSC::DatePrototype::DatePrototype): + * runtime/DatePrototype.h: + * runtime/ErrorConstructor.cpp: + (JSC::ErrorConstructor::ErrorConstructor): + * runtime/ErrorConstructor.h: + * runtime/ErrorInstance.cpp: + (JSC::ErrorInstance::ErrorInstance): + * runtime/ErrorInstance.h: + * runtime/ErrorPrototype.cpp: + (JSC::ErrorPrototype::ErrorPrototype): + * runtime/ErrorPrototype.h: + * runtime/FunctionConstructor.cpp: + (JSC::FunctionConstructor::FunctionConstructor): + * runtime/FunctionConstructor.h: + * runtime/FunctionPrototype.cpp: + (JSC::FunctionPrototype::FunctionPrototype): + * runtime/FunctionPrototype.h: + * runtime/GlobalEvalFunction.cpp: + (JSC::GlobalEvalFunction::GlobalEvalFunction): + * runtime/GlobalEvalFunction.h: + * runtime/InternalFunction.cpp: + (JSC::InternalFunction::InternalFunction): + * runtime/InternalFunction.h: + (JSC::InternalFunction::InternalFunction): + * runtime/JSActivation.cpp: + (JSC::JSActivation::JSActivation): + * runtime/JSActivation.h: + (JSC::JSActivation::JSActivationData::JSActivationData): + * runtime/JSArray.cpp: + (JSC::JSArray::JSArray): + * runtime/JSArray.h: + * runtime/JSByteArray.cpp: + (JSC::JSByteArray::JSByteArray): + * runtime/JSByteArray.h: + * runtime/JSFunction.cpp: + (JSC::JSFunction::JSFunction): + * runtime/JSFunction.h: + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::JSGlobalObject): + * runtime/JSONObject.h: + (JSC::JSONObject::JSONObject): + * runtime/JSObject.h: + (JSC::JSObject::JSObject): + (JSC::JSObject::setStructure): + * runtime/JSVariableObject.h: + (JSC::JSVariableObject::JSVariableObject): + * runtime/JSWrapperObject.h: + (JSC::JSWrapperObject::JSWrapperObject): + * runtime/MathObject.cpp: + (JSC::MathObject::MathObject): + * runtime/MathObject.h: + * runtime/NativeErrorConstructor.cpp: + (JSC::NativeErrorConstructor::NativeErrorConstructor): + * runtime/NativeErrorConstructor.h: + * runtime/NativeErrorPrototype.cpp: + (JSC::NativeErrorPrototype::NativeErrorPrototype): + * runtime/NativeErrorPrototype.h: + * runtime/NumberConstructor.cpp: + (JSC::NumberConstructor::NumberConstructor): + * runtime/NumberConstructor.h: + * runtime/NumberObject.cpp: + (JSC::NumberObject::NumberObject): + * runtime/NumberObject.h: + * runtime/NumberPrototype.cpp: + (JSC::NumberPrototype::NumberPrototype): + * runtime/NumberPrototype.h: + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::ObjectConstructor): + * runtime/ObjectConstructor.h: + * runtime/ObjectPrototype.cpp: + (JSC::ObjectPrototype::ObjectPrototype): + * runtime/ObjectPrototype.h: + * runtime/PropertyNameArray.h: + (JSC::PropertyNameArrayData::setCachedPrototypeChain): + * runtime/PrototypeFunction.cpp: + (JSC::PrototypeFunction::PrototypeFunction): + * runtime/PrototypeFunction.h: + * runtime/RegExpConstructor.cpp: + (JSC::RegExpConstructor::RegExpConstructor): + * runtime/RegExpConstructor.h: + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::RegExpObject): + * runtime/RegExpObject.h: + (JSC::RegExpObject::RegExpObjectData::RegExpObjectData): + * runtime/RegExpPrototype.cpp: + (JSC::RegExpPrototype::RegExpPrototype): + * runtime/RegExpPrototype.h: + * runtime/StringConstructor.cpp: + (JSC::StringConstructor::StringConstructor): + * runtime/StringConstructor.h: + * runtime/StringObject.cpp: + (JSC::StringObject::StringObject): + * runtime/StringObject.h: + * runtime/StringObjectThatMasqueradesAsUndefined.h: + (JSC::StringObjectThatMasqueradesAsUndefined::StringObjectThatMasqueradesAsUndefined): + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::StringPrototype): + * runtime/StringPrototype.h: + * wtf/PassRefPtr.h: + (WTF::NotNullPassRefPtr::NotNullPassRefPtr): + (WTF::NotNullPassRefPtr::~NotNullPassRefPtr): + (WTF::NotNullPassRefPtr::get): + (WTF::NotNullPassRefPtr::clear): + (WTF::NotNullPassRefPtr::releaseRef): + (WTF::NotNullPassRefPtr::operator*): + (WTF::NotNullPassRefPtr::operator->): + (WTF::NotNullPassRefPtr::operator!): + (WTF::NotNullPassRefPtr::operator UnspecifiedBoolType): + * wtf/RefPtr.h: + (WTF::RefPtr::RefPtr): + (WTF::operator==): + +2009-09-28 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Hard dependency on SSE2 instruction set with JIT + https://bugs.webkit.org/show_bug.cgi?id=29779 + + Add floating point support checks to op_jfalse and op_jtrue, and + fix the logic for the slow case of op_add + + * jit/JITArithmetic.cpp: + (JSC::JIT::emitSlow_op_add): + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_jfalse): + (JSC::JIT::emit_op_jtrue): + +2009-09-28 Yaar Schnitman <yaar@chromium.org> + + Reviewed by Dimitri Glazkov. + + Chromium port - recognize we are being built independently + of chromium and look for dependencies under webkit/chromium rather + than chromium/src. + + https://bugs.webkit.org/show_bug.cgi?id=29722 + + * JavaScriptCore.gyp/JavaScriptCore.gyp: + +2009-09-28 Jakub Wieczorek <faw217@gmail.com> + + Reviewed by Simon Hausmann. + + [Qt] Implement XSLT support with QtXmlPatterns. + https://bugs.webkit.org/show_bug.cgi?id=28303 + + * wtf/Platform.h: Add a WTF_USE_QXMLQUERY #define. + +2009-09-28 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Simon Hausmann. + + Remove __clear_cache which is an internal function of GCC + https://bugs.webkit.org/show_bug.cgi?id=28886 + + Although __clear_cache is exported from GCC, this is an internal + function. GCC makes no promises about it. + + * jit/ExecutableAllocator.h: + (JSC::ExecutableAllocator::cacheFlush): + +2009-09-28 Sam Weinig <sam@webkit.org> + + Reviewed by Oliver Hunt. + + Fix an absolute path to somewhere in Oliver's machine to a relative path + for derived JSONObject.lut.h. + + * JavaScriptCore.xcodeproj/project.pbxproj: + +2009-09-28 Joerg Bornemann <joerg.bornemann@nokia.com> + + Reviewed by Simon Hausmann. + + Add ARM version detection for Windows CE. + + * wtf/Platform.h: + +2009-09-26 Yongjun Zhang <yongjun.zhang@nokia.com> + + Reviewed by Simon Hausmann. + + Add MarkStackSymbian.cpp to build JavascriptCore for Symbian. + + Re-use Windows shrinkAllocation implementation because Symbian doesn't + support releasing part of memory region. + + Use fastMalloc and fastFree to implement allocateStack and releaseStack + for Symbian port. + + * JavaScriptCore.pri: + * runtime/MarkStack.h: + (JSC::MarkStack::MarkStackArray::shrinkAllocation): + * runtime/MarkStackSymbian.cpp: Added. + (JSC::MarkStack::initializePagesize): + (JSC::MarkStack::allocateStack): + (JSC::MarkStack::releaseStack): + +2009-09-25 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Fix unaligned data access in YARR_JIT on ARMv5 and below. + https://bugs.webkit.org/show_bug.cgi?id=29695 + + On ARMv5 and below all data access should be naturally aligned. + In the YARR_JIT there is a case when character pairs are + loaded from the input string, but this data access is not + naturally aligned. This fix introduces load32WithUnalignedHalfWords + and branch32WithUnalignedHalfWords functions which contain + naturally aligned memory loads - half word loads - on ARMv5 and below. + + * assembler/MacroAssemblerARM.cpp: + (JSC::MacroAssemblerARM::load32WithUnalignedHalfWords): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::load32WithUnalignedHalfWords): + (JSC::MacroAssemblerARM::branch32WithUnalignedHalfWords): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::load32WithUnalignedHalfWords): + (JSC::MacroAssemblerARMv7::branch32): + (JSC::MacroAssemblerARMv7::branch32WithUnalignedHalfWords): + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::load32WithUnalignedHalfWords): + (JSC::MacroAssemblerX86Common::branch32WithUnalignedHalfWords): + * wtf/Platform.h: + * yarr/RegexJIT.cpp: + (JSC::Yarr::RegexGenerator::generatePatternCharacterPair): + +2009-09-25 Jeremy Orlow <jorlow@chromium.org> + + This is breaking Chromium try bots, so I'm counting this as a build fix. + + Add more svn:ignore exceptions. On different platforms, these files are + generated with different case for JavaScriptCore. Also there are some + wtf project files that get built apparently. + + * JavaScriptCore.gyp: Changed property svn:ignore. + +2009-09-25 Ada Chan <adachan@apple.com> + + Build fix. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-25 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Darin Adler. + + Inlined some object creation code, including lexicalGlobalObject access + https://bugs.webkit.org/show_bug.cgi?id=29750 + + SunSpider says 0.5% faster. + + 0.8% speedup on bench-alloc-nonretained.js. + 2.5% speedup on v8-splay.js. + + * interpreter/CachedCall.h: + (JSC::CachedCall::CachedCall): + * interpreter/CallFrame.h: + (JSC::ExecState::lexicalGlobalObject): + (JSC::ExecState::globalThisValue): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::dumpRegisters): + (JSC::Interpreter::execute): + (JSC::Interpreter::privateExecute): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * runtime/FunctionConstructor.cpp: + (JSC::constructFunction): + * runtime/ScopeChain.cpp: + (JSC::ScopeChainNode::print): + * runtime/ScopeChain.h: + (JSC::ScopeChainNode::ScopeChainNode): + (JSC::ScopeChainNode::~ScopeChainNode): + (JSC::ScopeChainNode::push): + (JSC::ScopeChain::ScopeChain): + (JSC::ScopeChain::globalObject): Added a globalObject data member to ScopeChainNode. + Replaced accessor function for globalObject() with data member. Replaced + globalThisObject() accessor with direct access to globalThis, to match. + + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::init): + * runtime/JSGlobalObject.h: Inlined array and object construction. + +2009-09-25 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Gavin Barraclough. + + Add ARM version detection rules for Symbian + https://bugs.webkit.org/show_bug.cgi?id=29715 + + * wtf/Platform.h: + +2009-09-24 Xan Lopez <xlopez@igalia.com> + + Reviewed by Mark "Do It!" Rowe. + + Some GCC versions don't like C++-style comments in preprocessor + directives, change to C-style to shut them up. + + * wtf/Platform.h: + +2009-09-24 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Division is needlessly slow in 64-bit + https://bugs.webkit.org/show_bug.cgi?id=29723 + + Add codegen for op_div on x86-64 + + * jit/JIT.cpp: + (JSC::JIT::privateCompileMainPass): + (JSC::JIT::privateCompileSlowCases): + * jit/JIT.h: + * jit/JITArithmetic.cpp: + (JSC::JIT::compileBinaryArithOpSlowCase): + (JSC::JIT::emit_op_div): + (JSC::JIT::emitSlow_op_div): + * jit/JITInlineMethods.h: + (JSC::JIT::isOperandConstantImmediateDouble): + (JSC::JIT::addressFor): + (JSC::JIT::emitLoadDouble): + (JSC::JIT::emitLoadInt32ToDouble): + (JSC::JIT::emitJumpSlowCaseIfNotImmediateNumber): + +2009-09-24 Jeremy Orlow <jorlow@chromium.org> + + Reviewed by Dimitri Glazkov. + + Add GYP generated files to svn:ignore + https://bugs.webkit.org/show_bug.cgi?id=29724 + + Adding the following files to the svn:ignore list (all in the + JavaScriptCore/JavaScriptCore.gyp directory) + + JavaScriptCore.xcodeproj + JavaScriptCore.sln + JavaScriptCore.vcproj + JavaScriptCore_Debug.rules + JavaScriptCore_Release.rules + JavaScriptCore_Release - no tcmalloc.rules + JavaScriptCore_Purify.rules + JavaScriptCore.mk + JavaScriptCore_Debug_rules.mk + JavaScriptCore_Release_rules.mk + JavaScriptCore_Release - no tcmalloc_rules.mk + JavaScriptCore_Purify_rules.mk + JavaScriptCore.scons + JavaScriptCore_main.scons + + * JavaScriptCore.gyp: Changed property svn:ignore. + +2009-09-24 Yong Li <yong.li@torchmobile.com> + + Reviewed by Adam Barth. + + Replace platform-dependent code with WTF::currentTime() + https://bugs.webkit.org/show_bug.cgi?id=29148 + + * jsc.cpp: + (StopWatch::start): + (StopWatch::stop): + (StopWatch::getElapsedMS): + * runtime/TimeoutChecker.cpp: + (JSC::getCPUTime): + +2009-09-24 Mark Rowe <mrowe@apple.com> + + Reviewed by Sam Weinig. + + <rdar://problem/7215058> FastMalloc scavenging thread should be named + + * wtf/FastMalloc.cpp: + (WTF::TCMalloc_PageHeap::scavengerThread): Set the thread name. + * wtf/Platform.h: Move the knowledge of whether pthread_setname_np exists to here as HAVE(PTHREAD_SETNAME_NP). + * wtf/ThreadingPthreads.cpp: + (WTF::setThreadNameInternal): Use HAVE(PTHREAD_SETNAME_NP). + +2009-09-24 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Renamed clear to removeAll, as suggested by Darin Adler. + + * wtf/HashCountedSet.h: + (WTF::::removeAll): + +2009-09-24 Mark Rowe <mrowe@apple.com> + + Reviewed by Gavin Barraclough. + + Fix FastMalloc to build with assertions enabled. + + * wtf/FastMalloc.cpp: + (WTF::TCMalloc_Central_FreeList::ReleaseToSpans): + * wtf/TCSpinLock.h: + (TCMalloc_SpinLock::IsHeld): + +2009-09-24 Geoffrey Garen <ggaren@apple.com> + + Suggested by Darin Adler. + + Removed some unnecessary parameter names. + + * wtf/HashCountedSet.h: + +2009-09-24 Janne Koskinen <janne.p.koskinen@digia.com> + + Reviewed by Simon Hausmann. + + On Windows JSChar is typedef'ed to wchar_t. + + When building with WINSCW for Symbian we need to do the + same typedef. + + * API/JSStringRef.h: + +2009-09-23 Geoffrey Garen <ggaren@apple.com> + + A piece of my last patch that I forgot. + + * wtf/HashCountedSet.h: + (WTF::::clear): Added HashCountedSet::clear. + +2009-09-24 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Avoid __clear_cache built-in function if DISABLE_BUILTIN_CLEAR_CACHE define is set + https://bugs.webkit.org/show_bug.cgi?id=28886 + + There are some GCC packages (for example GCC-2006q3 from CodeSourcery) + which contain __clear_cache built-in function only for C while the C++ + version of __clear_cache is missing on ARM architectures. + + Fixed a small bug in the inline assembly of cacheFlush function on + ARM_TRADITIONAL. + + * jit/ExecutableAllocator.h: + (JSC::ExecutableAllocator::cacheFlush): + +2009-09-23 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Sam Weinig. + + Added the ability to swap vectors with inline capacities, so you can + store a vector with inline capacity in a hash table. + + * wtf/Vector.h: + (WTF::swap): + (WTF::VectorBuffer::swap): + +2009-09-23 David Kilzer <ddkilzer@apple.com> + + Move definition of USE(PLUGIN_HOST_PROCESS) from WebKitPrefix.h to Platform.h + + Reviewed by Mark Rowe. + + * wtf/Platform.h: Define WTF_USE_PLUGIN_HOST_PROCESS to 1 when + building on 64-bit SnowLeopard. Define to 0 elsewhere. + +2009-09-22 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Code sampling builds are broken. + https://bugs.webkit.org/show_bug.cgi?id=29662 + + Fix build. + + * bytecode/EvalCodeCache.h: + (JSC::EvalCodeCache::get): + * bytecode/SamplingTool.cpp: + (JSC::ScriptSampleRecord::sample): + (JSC::SamplingTool::doRun): + (JSC::SamplingTool::notifyOfScope): + (JSC::compareScriptSampleRecords): + (JSC::SamplingTool::dump): + * bytecode/SamplingTool.h: + (JSC::ScriptSampleRecord::ScriptSampleRecord): + (JSC::ScriptSampleRecord::~ScriptSampleRecord): + (JSC::SamplingTool::SamplingTool): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitNewFunction): + (JSC::BytecodeGenerator::emitNewFunctionExpression): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::makeFunction): + * debugger/Debugger.cpp: + (JSC::evaluateInGlobalCallFrame): + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::evaluate): + * parser/Nodes.cpp: + (JSC::ScopeNode::ScopeNode): + * runtime/Completion.cpp: + (JSC::checkSyntax): + (JSC::evaluate): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::fromGlobalCode): + * runtime/Executable.h: + (JSC::ScriptExecutable::ScriptExecutable): + (JSC::EvalExecutable::EvalExecutable): + (JSC::EvalExecutable::create): + (JSC::ProgramExecutable::ProgramExecutable): + (JSC::FunctionExecutable::create): + (JSC::FunctionExecutable::FunctionExecutable): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncEval): + +2009-09-22 Darin Adler <darin@apple.com> + + Reviewed by Sam Weinig. + + * wtf/Forward.h: Added PassOwnPtr. + +2009-09-22 Yaar Schnitman <yaar@chromium.org> + + Reviewed by David Levin. + + Ported chromium.org's javascriptcore.gyp for the webkit chromium port. + + https://bugs.webkit.org/show_bug.cgi?id=29617 + + * JavaScriptCore.gyp/JavaScriptCore.gyp: Added. + +2009-09-22 Thiago Macieira <thiago.macieira@nokia.com> + + Reviewed by Simon Hausmann. + + Fix compilation with WINSCW: no varargs macros + + Disable variadic arguments for WINSCW just like we do + for MSVC7. + + * wtf/Assertions.h: + +2009-09-22 Kent Hansen <khansen@trolltech.com> + + Reviewed by Simon Hausmann. + + Disable variadic macros on MSVC7. + + This was originally added in r26589 but not extended + when LOG_DISABLED/ASSERT_DISABLED was introduced. + + * wtf/Assertions.h: + +2009-09-22 Simon Hausmann <simon.hausmann@nokia.com> + + Unreviewed build fix for Windows CE < 5 + + Define WINCEBASIC to disable the IsDebuggerPresent() code in + wtf/Assertions.cpp. + + * JavaScriptCore.pri: + +2009-09-22 Joerg Bornemann <joerg.bornemann@nokia.com> + + Reviewed by Simon Hausmann. + + Fix major memory leak in JavaScriptCore RegisterFile on Windows CE + + https://bugs.webkit.org/show_bug.cgi?id=29367 + + On Widows CE we must decommit all committed pages before we release + them. See VirtualFree documentation. + Desktop Windows behaves much smoother in this situation. + + * interpreter/RegisterFile.cpp: + (JSC::RegisterFile::~RegisterFile): + +2009-09-21 Greg Bolsinga <bolsinga@apple.com> + + Reviewed by Simon Fraser & Sam Weinig. + + Add ENABLE(ORIENTATION_EVENTS) + https://bugs.webkit.org/show_bug.cgi?id=29508 + + * wtf/Platform.h: Also sort PLATFORM(IPHONE) #defines. + +2009-09-21 Jedrzej Nowacki <jedrzej.nowacki@nokia.com> + + Reviewed by Eric Seidel. + + [Fix] SourceCode's uninitialized member + + Potential source of crashes and bugs was fixed. Default constructor + didn't initialized m_provider member. + + https://bugs.webkit.org/show_bug.cgi?id=29364 + + * parser/SourceCode.h: + (JSC::SourceCode::SourceCode): + +2009-09-21 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + REGRESSION (r48582): Crash in StructureStubInfo::initPutByIdTransition when reloading trac.webkit.org + https://bugs.webkit.org/show_bug.cgi?id=29599 + + It is unsafe to attempt to cache new property transitions on + dictionaries of any type. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::tryCachePutByID): + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCachePutByID): + +2009-09-21 Oliver Hunt <oliver@apple.com> + + RS=Maciej Stachowiak. + + Re-land SNES fix with corrected assertion. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::resolveGlobal): + (JSC::Interpreter::tryCachePutByID): + (JSC::Interpreter::tryCacheGetByID): + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCachePutByID): + (JSC::JITThunks::tryCacheGetByID): + (JSC::DEFINE_STUB_FUNCTION): + * runtime/BatchedTransitionOptimizer.h: + (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): + * runtime/JSObject.cpp: + (JSC::JSObject::removeDirect): + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::getEnumerablePropertyNames): + (JSC::Structure::despecifyDictionaryFunction): + (JSC::Structure::addPropertyTransitionToExistingStructure): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::removePropertyTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::toCacheableDictionaryTransition): + (JSC::Structure::toUncacheableDictionaryTransition): + (JSC::Structure::fromDictionaryTransition): + (JSC::Structure::removePropertyWithoutTransition): + * runtime/Structure.h: + (JSC::Structure::isDictionary): + (JSC::Structure::isUncacheableDictionary): + (JSC::Structure::): + * runtime/StructureChain.cpp: + (JSC::StructureChain::isCacheable): + +2009-09-21 Adam Roben <aroben@apple.com> + + Revert r48573, as it caused many assertion failures + + * interpreter/Interpreter.cpp: + * jit/JITStubs.cpp: + * runtime/BatchedTransitionOptimizer.h: + * runtime/JSObject.cpp: + * runtime/Structure.cpp: + * runtime/Structure.h: + * runtime/StructureChain.cpp: + +2009-09-21 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk> + + Unreviewed make dist build fix. Missing files. + + * GNUmakefile.am: + +2009-09-19 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Sam 'Cabin Boy' Weinig. + + Fix stack alignment with ARM THUMB2 JIT. + https://bugs.webkit.org/show_bug.cgi?id=29526 + + Stack is currently being decremented by 0x3c, bump this to 0x40 to make this a + multiple of 16 bytes. + + * jit/JITStubs.cpp: + (JSC::JITThunks::JITThunks): + * jit/JITStubs.h: + +2009-09-20 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + SNES is too slow + https://bugs.webkit.org/show_bug.cgi?id=29534 + + The problem was that the emulator used multiple classes with + more properties than our dictionary cutoff allowed, this resulted + in more or less all critical logic inside the emulator requiring + uncached property access. + + Rather than simply bumping the dictionary cutoff, this patch + recognises that there are two ways to create a "dictionary" + structure. Either by adding a large number of properties, or + by removing a property. In the case of adding properties we + know all the existing properties will maintain their existing + offsets, so we could cache access to those properties, if we + know they won't be removed. + + To make this possible, this patch adds the logic required to + distinguish a dictionary created by addition from one created + by removal. With this logic in place we can now cache access + to objects with large numbers of properties. + + SNES performance improved by more than 6x. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::resolveGlobal): + (JSC::Interpreter::tryCachePutByID): + (JSC::Interpreter::tryCacheGetByID): + * jit/JITStubs.cpp: + (JSC::JITThunks::tryCachePutByID): + (JSC::JITThunks::tryCacheGetByID): + (JSC::DEFINE_STUB_FUNCTION): + * runtime/BatchedTransitionOptimizer.h: + (JSC::BatchedTransitionOptimizer::BatchedTransitionOptimizer): + * runtime/JSObject.cpp: + (JSC::JSObject::removeDirect): + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::getEnumerablePropertyNames): + (JSC::Structure::despecifyDictionaryFunction): + (JSC::Structure::addPropertyTransitionToExistingStructure): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::removePropertyTransition): + (JSC::Structure::toDictionaryTransition): + (JSC::Structure::toCacheableDictionaryTransition): + (JSC::Structure::toUncacheableDictionaryTransition): + (JSC::Structure::fromDictionaryTransition): + (JSC::Structure::removePropertyWithoutTransition): + * runtime/Structure.h: + (JSC::Structure::isDictionary): + (JSC::Structure::isUncacheableDictionary): + (JSC::Structure::): + * runtime/StructureChain.cpp: + (JSC::StructureChain::isCacheable): + +2009-09-19 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Implement ES5 Object.create function + https://bugs.webkit.org/show_bug.cgi?id=29524 + + Implement Object.create. Very simple patch, effectively Object.defineProperties + only creating the target object itself. + + * runtime/CommonIdentifiers.h: + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::ObjectConstructor): + (JSC::objectConstructorCreate): + +2009-09-19 Dan Bernstein <mitz@apple.com> + + Fix clean debug builds. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-19 Joerg Bornemann <joerg.bornemann@nokia.com> + + Reviewed by George Staikos. + + QtWebKit Windows CE compile fix + + https://bugs.webkit.org/show_bug.cgi?id=29379 + + There is no _aligned_alloc or _aligned_free on Windows CE. + We just use the Windows code that was there before and use VirtualAlloc. + But that also means that the BLOCK_SIZE must be 64K as this function + allocates on 64K boundaries. + + * runtime/Collector.cpp: + (JSC::Heap::allocateBlock): + (JSC::Heap::freeBlock): + * runtime/Collector.h: + +2009-09-19 Oliver Hunt <oliver@apple.com> + + Reviewed by Sam Weinig. + + Implement ES5 Object.defineProperties function + https://bugs.webkit.org/show_bug.cgi?id=29522 + + Implement Object.defineProperties. Fairly simple patch, simply makes use of + existing functionality used for defineProperty. + + * runtime/CommonIdentifiers.h: + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::ObjectConstructor): + (JSC::defineProperties): + (JSC::objectConstructorDefineProperties): + +2009-09-19 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fix). + + Windows build fix part2 + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-19 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Buildfix). + + Windows build fix part 1. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-18 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Implement ES5 Object.defineProperty function + https://bugs.webkit.org/show_bug.cgi?id=29503 + + Implement Object.defineProperty. This requires adding the API to + ObjectConstructor, along with a helper function that implements the + ES5 internal [[ToPropertyDescriptor]] function. It then adds + JSObject::defineOwnProperty that implements the appropriate ES5 semantics. + Currently defineOwnProperty uses a delete followed by a put to redefine + attributes of a property, clearly this is less efficient than it could be + but we can improve this if it needs to be possible in future. + + * JavaScriptCore.exp: + * debugger/DebuggerActivation.cpp: + (JSC::DebuggerActivation::defineGetter): + (JSC::DebuggerActivation::defineSetter): + * debugger/DebuggerActivation.h: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * jit/JITStubs.cpp: + Update defineGetter/Setter calls + * runtime/CommonIdentifiers.h: + * runtime/JSArray.cpp: + (JSC::JSArray::getOwnPropertySlot): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::defineGetter): + (JSC::JSGlobalObject::defineSetter): + * runtime/JSGlobalObject.h: + * runtime/JSObject.cpp: + (JSC::JSObject::defineGetter): + (JSC::JSObject::defineSetter): + (JSC::putDescriptor): + (JSC::JSObject::defineOwnProperty): + * runtime/JSObject.h: + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::ObjectConstructor): + (JSC::objectConstructorGetOwnPropertyDescriptor): + (JSC::toPropertyDescriptor): + (JSC::objectConstructorDefineProperty): + * runtime/ObjectPrototype.cpp: + (JSC::objectProtoFuncDefineGetter): + (JSC::objectProtoFuncDefineSetter): + * runtime/PropertyDescriptor.cpp: + (JSC::PropertyDescriptor::writable): + (JSC::PropertyDescriptor::enumerable): + (JSC::PropertyDescriptor::configurable): + (JSC::PropertyDescriptor::isDataDescriptor): + (JSC::PropertyDescriptor::isGenericDescriptor): + (JSC::PropertyDescriptor::isAccessorDescriptor): + (JSC::PropertyDescriptor::getter): + (JSC::PropertyDescriptor::setter): + (JSC::PropertyDescriptor::setDescriptor): + (JSC::PropertyDescriptor::setAccessorDescriptor): + (JSC::PropertyDescriptor::setWritable): + (JSC::PropertyDescriptor::setEnumerable): + (JSC::PropertyDescriptor::setConfigurable): + (JSC::PropertyDescriptor::setSetter): + (JSC::PropertyDescriptor::setGetter): + (JSC::PropertyDescriptor::equalTo): + (JSC::PropertyDescriptor::attributesEqual): + (JSC::PropertyDescriptor::attributesWithOverride): + * runtime/PropertyDescriptor.h: + (JSC::PropertyDescriptor::PropertyDescriptor): + (JSC::PropertyDescriptor::value): + (JSC::PropertyDescriptor::setValue): + (JSC::PropertyDescriptor::isEmpty): + (JSC::PropertyDescriptor::writablePresent): + (JSC::PropertyDescriptor::enumerablePresent): + (JSC::PropertyDescriptor::configurablePresent): + (JSC::PropertyDescriptor::setterPresent): + (JSC::PropertyDescriptor::getterPresent): + (JSC::PropertyDescriptor::operator==): + (JSC::PropertyDescriptor::): + +2009-09-18 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Build fix to enable ARM_THUMB2 on Linux + https://bugs.webkit.org/show_bug.cgi?id= + + * jit/ExecutableAllocator.h: + (JSC::ExecutableAllocator::cacheFlush): + * jit/JITStubs.cpp: + * wtf/Platform.h: + +2009-09-18 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Defines two pseudo-platforms for ARM and Thumb-2 instruction set. + https://bugs.webkit.org/show_bug.cgi?id=29122 + + Introduces WTF_PLATFORM_ARM_TRADITIONAL and WTF_PLATFORM_ARM_THUMB2 + macros on ARM platforms. The PLATFORM(ARM_THUMB2) should be used + when Thumb-2 instruction set is the required target. The + PLATFORM(ARM_TRADITIONAL) is for generic ARM instruction set. In + case where the code is common the PLATFORM(ARM) have to be used. + + * assembler/ARMAssembler.cpp: + * assembler/ARMAssembler.h: + * assembler/ARMv7Assembler.h: + * assembler/MacroAssembler.h: + * assembler/MacroAssemblerARM.cpp: + * assembler/MacroAssemblerARM.h: + * assembler/MacroAssemblerCodeRef.h: + (JSC::MacroAssemblerCodePtr::MacroAssemblerCodePtr): + * jit/ExecutableAllocator.h: + * jit/JIT.h: + * jit/JITInlineMethods.h: + (JSC::JIT::beginUninterruptedSequence): + (JSC::JIT::preserveReturnAddressAfterCall): + (JSC::JIT::restoreReturnAddressBeforeReturn): + (JSC::JIT::restoreArgumentReference): + (JSC::JIT::restoreArgumentReferenceForTrampoline): + * jit/JITOpcodes.cpp: + * jit/JITStubs.cpp: + (JSC::JITThunks::JITThunks): + * jit/JITStubs.h: + * wtf/Platform.h: + * yarr/RegexJIT.cpp: + (JSC::Yarr::RegexGenerator::generateEnter): + +2009-09-18 Joerg Bornemann <joerg.bornemann@nokia.com> + + Reviewed by Simon Hausmann. + + Fix the Qt/Windows CE build. + + * JavaScriptCore.pri: Build the ce_time.cpp functions from + within Qt externally. + * wtf/DateMath.cpp: Removed unnecessary Qt #ifdef, for the + Qt build these functions are no external, too. + +2009-09-17 Janne Koskinen <janne.p.koskinen@digia.com> + + Reviewed by Simon Hausmann. + + Symbian/WINSCW build fox. + + Repeat Q_OS_WIN wchar_t hack for WINSCW, similar to + revision 24774. + + WINSCW defines wchar_t, thus UChar has to be wchar_t + + * wtf/unicode/qt4/UnicodeQt4.h: + +2009-09-17 Janne Koskinen <janne.p.koskinen@digia.com> + + Reviewed by Simon Hausmann. + + Symbian/WINSCW build fix. + + https://bugs.webkit.org/show_bug.cgi?id=29186 + + WINSCW Template specialisation name in declaration must the be the same as in implementation. + + * runtime/LiteralParser.h: + +2009-09-15 Norbert Leser <norbert.leser@nokia.com> + + Reviewed by Darin Adler. + + https://bugs.webkit.org/show_bug.cgi?id=27060 + + Symbian compiler for emulator target (WINSCW) fails with + "illegal operand" for m_attributesInPrevious in structure.ccp + (when calling make_pair functions). + This error is apparently due to the compiler not properly + resolving the unsigned type of the declared bitfield. + + Initial patch explicitly casted m_attributesInPrevious + to unsigned, but since bitfield optimization is not critical for + the emulator target, this conditional change in header file + appears to be least intrusive. + + * runtime/Structure.h: + +2009-09-16 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Darin Adler. + + Fix GCC warnings on ARM_THUMB2 platform + + * assembler/ARMv7Assembler.h: + (JSC::ARMThumbImmediate::countLeadingZerosPartial): + * assembler/MacroAssemblerARMv7.h: + (JSC::MacroAssemblerARMv7::branchTruncateDoubleToInt32): + (JSC::MacroAssemblerARMv7::moveFixedWidthEncoding): + +2009-09-16 Greg Bolsinga <bolsinga@apple.com> + + Add ENABLE(INSPECTOR) + https://bugs.webkit.org/show_bug.cgi?id=29260 + + Reviewed by David Kilzer. + + * wtf/Platform.h: + +2009-09-16 Greg Bolsinga <bolsinga@apple.com> + + Add ENABLE(CONTEXT_MENUS) + https://bugs.webkit.org/show_bug.cgi?id=29225 + + Reviewed by David Kilzer. + + * wtf/Platform.h: + +2009-09-16 Benjamin C Meyer <benjamin.meyer@torchmobile.com> + + Reviewed by Eric Seidel. + + The webkit stdint and stdbool headers exists because + the compiler MSVC doesn't include them. The check + should not check for PLATFORM(WIN_OS) but for MSVC. + + * os-win32/stdbool.h: + * os-win32/stdint.h: + +2009-09-16 Greg Bolsinga <bolsinga@apple.com> + + Add ENABLE(DRAG_SUPPORT) + https://bugs.webkit.org/show_bug.cgi?id=29233 + + Reviewed by David Kilzer. + + * wtf/Platform.h: + +2009-09-16 Kevin Ollivier <kevino@theolliviers.com> + + waf build fix after flag was moved to correct place. + + * wscript: + +2009-09-16 Tor Arne Vestbø <tor.arne.vestbo@nokia.com> + + Reviewed by Simon Hausmann. + + [Qt] Build fix for 64-bit Qt on Mac OS X + + * wtf/Platform.h: Use JSVALUE64 on DARWIN, not only on MAC + +2009-09-16 Zoltan Herczeg <zherczeg@inf.u-szeged.hu> + + Reviewed by Simon Hausmann. + + [Qt] Fix wtf/ThreadSpecific.h under Qt to free thread local objects. + https://bugs.webkit.org/show_bug.cgi?id=29295 + + This is an important fix when JavaScript workers are in use, since + unfreed ThreadGlobalDatas leak a big amount of memory (50-100k each). + QThreadStorage calls the destructor of a given object, which is the + ThreadSpecific::Data. Unlike pthread, Qt is object oriented, and does + not support the calling of a static utility function when the thread + is about to close. In this patch we call the ThreadSpecific::destroy() + utility function from the destructor of ThreadSpecific::Data. Moreover, + since Qt resets all thread local values to 0 before the calling of the + appropriate destructors, we set back the pointer to its original value. + This is necessary because the get() method of the ThreadSpecific + object may be called during the exuction of the destructor. + + * wtf/ThreadSpecific.h: + (WTF::ThreadSpecific::Data::~Data): + (WTF::::~ThreadSpecific): + (WTF::::set): + (WTF::::destroy): + +2009-09-10 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Allow anonymous storage inside JSObject + https://bugs.webkit.org/show_bug.cgi?id=29168 + + Add the concept of anonymous slots to Structures so that it is + possible to store references to values that need marking in the + standard JSObject storage buffer. This allows us to reduce the + malloc overhead of some objects (by allowing them to store JS + values in the inline storage of the object) and reduce the + dependence of custom mark functions (if all an objects children + are in the standard object property storage there's no need to + mark them manually). + + * JavaScriptCore.exp: + * runtime/JSObject.h: + (JSC::JSObject::putAnonymousValue): + (JSC::JSObject::getAnonymousValue): + (JSC::JSObject::addAnonymousSlots): + * runtime/JSWrapperObject.h: + (JSC::JSWrapperObject::createStructure): + (JSC::JSWrapperObject::JSWrapperObject): + (JSC::JSWrapperObject::setInternalValue): + * runtime/PropertyMapHashTable.h: + * runtime/Structure.cpp: + (JSC::Structure::~Structure): + (JSC::Structure::materializePropertyMap): + (JSC::Structure::addAnonymousSlotsTransition): + (JSC::Structure::copyPropertyTable): + (JSC::Structure::put): + (JSC::Structure::rehashPropertyMapHashTable): + * runtime/Structure.h: + (JSC::Structure::propertyStorageSize): + (JSC::StructureTransitionTable::reifySingleTransition): + * runtime/StructureTransitionTable.h: + (JSC::StructureTransitionTable::TransitionTable::addSlotTransition): + (JSC::StructureTransitionTable::TransitionTable::removeSlotTransition): + (JSC::StructureTransitionTable::TransitionTable::getSlotTransition): + (JSC::StructureTransitionTable::getAnonymousSlotTransition): + (JSC::StructureTransitionTable::addAnonymousSlotTransition): + (JSC::StructureTransitionTable::removeAnonymousSlotTransition): + +2009-09-15 Alex Milowski <alex@milowski.com> + + Reviewed by Tor Arne Vestbø. + + Added the ENABLE_MATHML define to the features + + * Configurations/FeatureDefines.xcconfig: + +2009-09-15 Csaba Osztrogonac <oszi@inf.u-szeged.hu> + + Reviewed by Tor Arne Vestbø. + + [Qt] Build fix for windows. + + After http://trac.webkit.org/changeset/47795 the MinGW build broke, + because MinGW has __mingw_aligned_malloc instead of _aligned_malloc. + + * runtime/Collector.cpp: + (JSC::Heap::allocateBlock): MinGW case added. + (JSC::Heap::freeBlock): MinGW case added. + +2009-09-15 Csaba Osztrogonac <oszi@inf.u-szeged.hu> + + Reviewed by Tor Arne Vestbø. + + [Qt] Build fix for Windows/MinGW + + https://bugs.webkit.org/show_bug.cgi?id=29268 + + * wtf/Platform.h: JSVALUE32_64 temporarily disabled on PLATFORM(WIN_OS) with COMPILER(MINGW) + +2009-09-14 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Detect VFP at runtime in generic ARM port on Linux platform. + https://bugs.webkit.org/show_bug.cgi?id=29076 + + * JavaScriptCore.pri: + * assembler/MacroAssemblerARM.cpp: Added. + (JSC::isVFPPresent): + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::supportsFloatingPoint): + +2009-09-14 Csaba Osztrogonac <oszi@inf.u-szeged.hu> + + Reviewed by Tor Arne Vestbø. + + [Qt] Build fix for windows build. + + * JavaScriptCore.pri: Correct a logic error. + * pcre/dftables: Add missing paranthesis for tmpdir function. + +2009-09-12 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fix). + + Build fix for windows exports (again). + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-12 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fix). + + Build fix for windows exports. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-12 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fix). + + Correct fix for non-allinonefile builds + + * runtime/ObjectConstructor.cpp: + +2009-09-12 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fix). + + Fix non-allinonefile builds + + * runtime/ObjectConstructor.cpp: + +2009-09-12 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + [ES5] Implement Object.keys + https://bugs.webkit.org/show_bug.cgi?id=29170 + + This patch basically requires two separate steps, the first is to split getPropertyNames + into two functions -- getOwnPropertyNames and getPropertyNames, basically making them behave + in the same way as getOwnPropertySlot and getPropertySlot. In essence getOwnPropertyNames + produces the list of properties on an object excluding its prototype chain and getPropertyNames + just iterates the the object and its prototype chain calling getOwnPropertyNames at each level. + + * API/JSCallbackObject.h: + * API/JSCallbackObjectFunctions.h: + (JSC::::getOwnPropertyNames): + * JavaScriptCore.exp: + * debugger/DebuggerActivation.cpp: + (JSC::DebuggerActivation::getOwnPropertyNames): + * debugger/DebuggerActivation.h: + * runtime/CommonIdentifiers.h: + * runtime/JSArray.cpp: + (JSC::JSArray::getOwnPropertyNames): + * runtime/JSArray.h: + * runtime/JSByteArray.cpp: + (JSC::JSByteArray::getOwnPropertyNames): + * runtime/JSByteArray.h: + * runtime/JSNotAnObject.cpp: + (JSC::JSNotAnObject::getOwnPropertyNames): + * runtime/JSNotAnObject.h: + * runtime/JSObject.cpp: + (JSC::JSObject::getOwnPropertyNames): + * runtime/JSObject.h: + * runtime/JSVariableObject.cpp: + (JSC::JSVariableObject::getOwnPropertyNames): + * runtime/JSVariableObject.h: + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::ObjectConstructor): + (JSC::objectConstructorKeys): + * runtime/RegExpMatchesArray.h: + (JSC::RegExpMatchesArray::getOwnPropertyNames): + * runtime/StringObject.cpp: + (JSC::StringObject::getOwnPropertyNames): + * runtime/StringObject.h: + * runtime/Structure.cpp: + (JSC::Structure::getOwnEnumerablePropertyNames): + (JSC::Structure::getEnumerablePropertyNames): + * runtime/Structure.h: + +2009-09-11 Oliver Hunt <oliver@apple.com> + + Reviewed by Sam Weinig. + + getPropertyNames caching is invalid when the prototype chain contains objects with custom getPropertyNames + https://bugs.webkit.org/show_bug.cgi?id=29214 + + Add a flag to TypeInfo to indicate whether a type overrides getPropertyNames. + This flag is used to make sure that caching of the property name data is safe. + + * API/JSCallbackConstructor.h: + (JSC::JSCallbackConstructor::createStructure): + * debugger/DebuggerActivation.h: + (JSC::DebuggerActivation::createStructure): + * runtime/BooleanObject.h: + (JSC::BooleanObject::createStructure): + * runtime/DatePrototype.h: + (JSC::DatePrototype::createStructure): + * runtime/FunctionPrototype.h: + (JSC::FunctionPrototype::createStructure): + * runtime/JSONObject.h: + (JSC::JSONObject::createStructure): + * runtime/JSObject.h: + (JSC::JSObject::createStructure): + * runtime/JSTypeInfo.h: + (JSC::TypeInfo::hasDefaultGetPropertyNames): + * runtime/JSVariableObject.h: + (JSC::JSVariableObject::createStructure): + * runtime/JSWrapperObject.h: + (JSC::JSWrapperObject::createStructure): + * runtime/MathObject.h: + (JSC::MathObject::createStructure): + * runtime/NumberConstructor.h: + (JSC::NumberConstructor::createStructure): + * runtime/NumberObject.h: + (JSC::NumberObject::createStructure): + * runtime/RegExpConstructor.h: + (JSC::RegExpConstructor::createStructure): + * runtime/RegExpObject.h: + (JSC::RegExpObject::createStructure): + * runtime/StructureChain.cpp: + (JSC::StructureChain::isCacheable): + +2009-09-11 Alexey Proskuryakov <ap@webkit.org> + + Reviewed by Geoff Garen. + + https://bugs.webkit.org/show_bug.cgi?id=29207 + Add checks for using WebCore JS context on secondary threads + + * runtime/JSGlobalData.cpp: (JSC::JSGlobalData::JSGlobalData): + * runtime/JSGlobalData.h: + Added a new mainThreadOnly flag that WebCore would set. + + * runtime/Collector.cpp: (JSC::Heap::registerThread): JSC API methods always call this, + so this is a good place to check that the API isn't used form a wrong thread. + +2009-09-11 Jocelyn Turcotte <jocelyn.turcotte@nokia.com> + + Reviewed by Simon Hausmann. + + Compiling JavaScriptCore on sparc 64 with gcc fails. + + ThreadSafeShared uses the atomic __gnu_cxx::__exchange_and_add with an int, + however on sparc 64 the _Atomic_word argument is typedefed to long (8 bytes). + + The patch disables WTF_USE_LOCKFREE_THREADSAFESHARED in ThreadSafeShared to use + a mutex instead when compiling for sparc 64 with gcc. + + https://bugs.webkit.org/show_bug.cgi?id=29175 + + * wtf/Platform.h: + __sparc64__ is not defined on all OS. + Uses instead: __sparc__ && __arch64__ || __sparcv9 + * wtf/Threading.h: + +2009-09-11 Prasanth Ullattil <prasanth.ullattil@nokia.com> + + Reviewed by Simon Hausmann. + + Fix compile error on Windows7(64Bit) with latest SDK. + + Added the missing include file. + + * runtime/UString.cpp: + +2009-09-11 Joerg Bornemann <joerg.bornemann@trolltech.com> + + Reviewed by Simon Hausmann. + + Qt/Windows CE compile fix, include the executable allocator and + markstack implementation in the windows build. + + * JavaScriptCore.pri: + +2009-09-08 John Abd-El-Malek <jam@chromium.org> + + Reviewed by Dimitri Glazkov. + + Remove unneeded define for ActiveX. + https://bugs.webkit.org/show_bug.cgi?id=29054 + + * wtf/Platform.h: + +2009-09-10 Mark Rowe <mrowe@apple.com> + + Rubber-stamped by Sam Weinig. + + Update JavaScriptCore and WebKit's FeatureDefines.xcconfig so that they are in sync with WebCore as they need to be. + + * Configurations/FeatureDefines.xcconfig: + +2009-09-10 Fumitoshi Ukai <ukai@chromium.org> + + Reviewed by Alexey Proskuryakov. + + Export WTF::tryFastMalloc used in WebSocketChannel. + https://bugs.webkit.org/show_bug.cgi?id=28038 + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-10 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fix). + + Make StructureTransitionTable use an enum for the PtrAndFlags member + used for the single transition slot optimisation. + + * runtime/StructureTransitionTable.h: + (JSC::StructureTransitionTable::StructureTransitionTable): + (JSC::StructureTransitionTable::usingSingleTransitionSlot): + (JSC::StructureTransitionTable::): + +2009-09-10 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + Refactor StructureTransitionTable and Structure to unify handling of the single slot optimization + https://bugs.webkit.org/show_bug.cgi?id=29141 + + Make StructureTransitionTable encapsulate the single transition slot optimization. + + * runtime/Structure.cpp: + (JSC::Structure::Structure): + (JSC::Structure::~Structure): + (JSC::Structure::addPropertyTransitionToExistingStructure): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::addPropertyWithoutTransition): + (JSC::Structure::removePropertyWithoutTransition): + (JSC::Structure::hasTransition): + * runtime/Structure.h: + (JSC::StructureTransitionTable::contains): + (JSC::StructureTransitionTable::get): + (JSC::StructureTransitionTable::hasTransition): + (JSC::StructureTransitionTable::reifySingleTransition): + * runtime/StructureTransitionTable.h: + (JSC::StructureTransitionTable::StructureTransitionTable): + (JSC::StructureTransitionTable::~StructureTransitionTable): + (JSC::StructureTransitionTable::remove): + (JSC::StructureTransitionTable::add): + (JSC::StructureTransitionTable::table): + (JSC::StructureTransitionTable::singleTransition): + (JSC::StructureTransitionTable::usingSingleTransitionSlot): + (JSC::StructureTransitionTable::setSingleTransition): + (JSC::StructureTransitionTable::setTransitionTable): + (JSC::StructureTransitionTable::): + * wtf/PtrAndFlags.h: + (WTF::PtrAndFlags::PtrAndFlags): + +2009-09-10 Zoltan Horvath <zoltan@webkit.org> + + Reviewed by Darin Adler. + + Implement fastDeleteSkippingDestructor for FastAllocBase and fastDeleteAllValues for HashSet + https://bugs.webkit.org/show_bug.cgi?id=25930 + + FastAllocBase has been extended with fastDeleteSkippingDestructor function which + releases memory without destructor call. fastDeleteAllValues has been implemented + similar as deleteAllValues but it uses fastDelete function to release memory. + + * wtf/FastAllocBase.h: + (WTF::fastDeleteSkippingDestructor): + * wtf/HashSet.h: + (WTF::fastDeleteAllValues): + +2009-09-10 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Darin Adler. + + ARM compiler does not understand GCC visibility attribute + https://bugs.webkit.org/show_bug.cgi?id=29079 + + * API/JSBase.h: Make the test more specific to hit only + the GCC compiler + +2009-09-10 Adam Barth <abarth@webkit.org> + + Unreviewed revert of the previous change. It broke the tests. + + * wtf/dtoa.cpp: + (WTF::dtoa): + +2009-09-10 Ben Laurie <benl@google.com> + + Reviewed by Adam Barth. + + <https://bugs.webkit.org/show_bug.cgi?id=26836> + + If dtoa was given a small buffer and the number was either infinite or + NaN, then the buffer would be overflowed. + + * wtf/dtoa.cpp: + +2009-09-09 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Darin Adler. + + Change reinterpret_cast to static_cast in r48212. + + * jit/ExecutableAllocator.h: + (JSC::ExecutableAllocator::cacheFlush): + +2009-09-09 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Darin Adler. + + Remove WTF_PLATFORM_FORCE_PACK as it is no longer used + https://bugs.webkit.org/show_bug.cgi?id=29066 + + * wtf/Platform.h: + +2009-09-09 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Ariya Hidayat. + + Implement flushing the instruction cache for Symbian + https://bugs.webkit.org/show_bug.cgi?id=29075 + + * jit/ExecutableAllocator.h: + (JSC::ExecutableAllocator::cacheFlush): Call IMB_Range to flush + the instruction cache on Symbian + +2009-09-09 Kent Hansen <khansen@trolltech.com> + + Reviewed by Darin Adler. + + https://bugs.webkit.org/show_bug.cgi?id=29024 + Make JavaScriptCore compile on platforms with case-insensitive file systems and typeinfo.h in STL + + These platforms include Microsoft Visual Studio 2003, and Symbian with Metrowerks compiler. + + * JavaScriptCore.gypi: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/JSTypeInfo.h: Copied from JavaScriptCore/runtime/TypeInfo.h. + * runtime/Structure.h: + * runtime/TypeInfo.h: Removed. + +2009-09-08 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + JSON.stringify(Date) loses the milliseconds information + https://bugs.webkit.org/show_bug.cgi?id=29063 + + Make sure we include milliseconds in the output of toISOString. + + * runtime/DatePrototype.cpp: + (JSC::dateProtoFuncToISOString): + +2009-09-08 Kevin Ollivier <kevino@theolliviers.com> + + wx build fix, generate derived sources earlier in order to make sure + they're found by the build system when generating the list of sources to build. + + * wscript: + +2009-09-08 Laszlo Gombos <laszlo.1.gombos@nokia.com> + + Reviewed by Simon Hausmann. + + Build fix when USE(LOCKFREE_THREADSAFESHARED) is not defined + https://bugs.webkit.org/show_bug.cgi?id=29011 + + * wtf/Threading.h: Use LOCKFREE_THREADSAFESHARED guard for + atomicIncrement and atomicDecrement + +2009-09-07 Zoltan Horvath <zoltan@webkit.org> + + Reviewed by Darin Adler. + + Allow custom memory allocation control in Yarr's RegexInterpreter + https://bugs.webkit.org/show_bug.cgi?id=29025 + + Inherits RegexInterpreter classes from FastAllocBase (bug #20422), which has + been instantiated by 'new': + + class ByteDisjunction + -> instantiated in JavaScriptCore/yarr/RegexInterpreter.cpp:1462 + + struct BytecodePattern + -> instantiated in JavaScriptCore/yarr/RegexInterpreter.cpp:1279 + + * yarr/RegexInterpreter.h: + +2009-09-07 Drew Wilson <atwilson@google.com> + + Reverting r48121 to fix Windows build errors. + + * JavaScriptCore.exp: + +2009-09-07 Drew Wilson <atwilson@google.com> + + Reviewed by David Levin. + + Enable SHARED_WORKERS by default + https://bugs.webkit.org/show_bug.cgi?id=28959 + + * Configurations/FeatureDefines.xcconfig: + +2009-09-07 Fumitoshi Ukai <ukai@chromium.org> + + Reviewed by Alexey Proskuryakov. + + Export WTF::tryFastMalloc used in WebSocketChannel. + https://bugs.webkit.org/show_bug.cgi?id=28038 + + * JavaScriptCore.exp: + +2009-09-04 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fix). + + Fix windows export files + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-09-04 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + [[ToString]] conversion should use the actual toString function for String objects. + + Remove incorrect specialisations of toString conversions on StringObject. + + * JavaScriptCore.exp: + * runtime/StringObject.cpp: + * runtime/StringObject.h: + +2009-09-04 Steve Falkenburg <sfalken@apple.com> + + Windows build fix. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Add new export. + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: Add new export. + +2009-09-04 Steve Falkenburg <sfalken@apple.com> + + Windows build fix. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Remove unneeded export. + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: Remove unneeded export. + +2009-09-04 Darin Adler <darin@apple.com> + + Reviewed by Geoff Garen. + + DateInstance object collected on ARM JIT (JSValue: WTF_USE_JSVALUE32) + https://bugs.webkit.org/show_bug.cgi?id=28909 + + Part two. + + Make some improvements to garbage collection code: + + 1) Create a runtime assertion that catches any classes that + override markChildren but have the HasDefaultMark bit set. + 2) Remove checks of the mark bit outside the MarkStack::append + function; they are redundant. + 3) Improve the efficiency of the asObject and asArray functions + when called on JSCell* to avoid a round trip to JSValue. + 4) Make more callers use the checked asCell and asObject + casting functions rather than unchecked casts. + 5) Removed the JSCell::marked function and other GC-related + functions because these operations are no longer things that + code other than the core GC code needs to do directly. Fixed + callers that were calling them. + + * runtime/Collector.cpp: + (JSC::Heap::markConservatively): Removed unneeded call to MarkStack::drain. + (JSC::Heap::markProtectedObjects): Removed unneeded check of the mark + bit and call to MarkStack::drain. + (JSC::Heap::collect): Removed unneeded checks of the mark bit and also + changed call to SmallStrings::mark to call markChildren instead to match + the rest of the objects. + (JSC::typeName): Removed unneeded cast to JSObject*. + + * runtime/JSArray.h: + (JSC::asArray): Added an overload for JSCell* and changed the JSValue + version to call it. Removed some unneeded casts. + (JSC::JSArray::markChildrenDirect): Marked this function inline. It's in + a header, and if not marked inline this could lead to linking problems. + (JSC::MarkStack::markChildren): Added. This helper function is used by + the drain function to avoid repating code. Also added the code here to + check fro default mark violations in debug code. If a markChildren + function adds something to the mark stack, but the type info claimed + hasDefaultMark was true, then we will get an assertion now. Also fixed + the assertion about the mark bit to use the Heap function directly + because we don't have a JSCell::marked function any more. + (JSC::MarkStack::drain): Changed a local variable from "v" to "value", + and from "currentCell" to "cell". Changed to call markChildren in two + places instead of repeating a chain of if statements twice. Changed + code that reads and writes the mark bit to use Heap::isCellMarked and + Heap::markCell so we can eliminate the JSCell::marked and + JSCell::markCellDirect functions. + + * runtime/JSCell.h: Removed JSCell's markCellDirect and marked member + functions. Added a comment explaining that asCell should be deprecated + in favor of the JSValue asCell member function. + (JSC::MarkStack::append): Added the assertion that catches callers + that have set the HasDefaultMark bit incorrectly. Changed + code that reads and writes the mark bit to use Heap::isCellMarked and + Heap::markCell so we can eliminate the JSCell::marked and + JSCell::markCellDirect functions. Moved the overload of + MarkStack::append for JSValue here so it can call through to the cell + version. The old version had a copy of all the code instead, but that + repeated the conversion from JSValue to JSCell* and the check for + whether a value is a cell multiple times. + (JSC::Structure::markAggregate): Moved this function here to avoid + dependencies for Structure.h, since this calls MarkStack::append. + + * runtime/JSObject.cpp: + (JSC::JSObject::markChildren): Added code to clear + m_isCheckingForDefaultMarkViolation so the marking done by JSObject + doesn't trigger the assertion. + + * runtime/JSValue.h: Moved some stray includes that were outside the + header guard inside it. Not sure how that happened! Removed the + GC-related member functions markChildren, hasChildren, marked, and + markDirect. + + * runtime/JSWrapperObject.h: Made markChildren private. + (JSC::JSWrapperObject::createStructure): Added. Fixes a bug where the + HasDefaultMark bit was set. + + * runtime/MarkStack.h: Added m_isCheckingForDefaultMarkViolation and + initialized it to false. Moved the append function body from here to + JSCell.h. Added a declaration of a private markChildren function used + inside the drain function. + + * runtime/SmallStrings.cpp: + (JSC::SmallStrings::markChildren): Changed the name and style of this + function to match other functions. This allows us to share the normal + mark stack code path. + + * runtime/SmallStrings.h: Changed the name and interface of mark to + the more-normal markChildren style. + + * runtime/Structure.h: Moved the body of markAggregate into the + JSCell.h to avoid a circular dependency with JSCell.h. + +2009-09-04 Darin Adler <darin@apple.com> + + Reviewed by Geoff Garen. + + DateInstance object collected on ARM JIT (JSValue: WTF_USE_JSVALUE32) + https://bugs.webkit.org/show_bug.cgi?id=28909 + + Part one. + + Make some improvements to garbage collection code: + + 1) Fix the two classes that had the default mark bit set but + should not. + 2) Remove checks of the mark bit outside the MarkStack::append + function; they are redundant. + 3) Make more callers use the checked asCell and asObject + casting functions rather than unchecked casts. + 4) Removed some GC-related functions because these operations are + no longer things that code other than the core GC code needs + to do directly. Fixed callers that were calling them. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::markAggregate): Removed unneeded check of the mark + bit before calling MarkStack::append. + + * interpreter/Register.h: Removed unneeded marked and markChildren + functions. + + * jit/JITStubs.cpp: + (op_eq): Removed unneeded assertions, instead using checked casting + functions such as asObject. + + * runtime/ArgList.h: Added now-needed forward declaration of MarkStack. + + * runtime/GetterSetter.cpp: + (JSC::GetterSetter::markChildren): Remmoved unneeded check of the mark bit. + + * runtime/GlobalEvalFunction.h: + (JSC::GlobalEvalFunction::createStructure): Added. Fixes a bug where the + HasDefaultMark bit was set. + + * runtime/JSCell.cpp: + (JSC::JSCell::getObject): Use asObject to avoid a direct static_cast. + + * runtime/JSObject.h: + (JSC::asObject): Added an overload for JSCell* and changed the JSValue + version to call it. + (JSC::JSValue::get): Use asObject to avoid a direct static_cast. + + * runtime/JSWrapperObject.h: Made markChildren private. + (JSC::JSWrapperObject::createStructure): Added. Fixes a bug where the + HasDefaultMark bit was set. Later we may want to optimize this for + wrapper types that never have cells in their internal values, but there + is no measured performance regression in SunSpider or V8 doing this + all the time. + + * runtime/MarkStack.cpp: Tweaked formatting. + +2009-09-04 Kevin Ollivier <kevino@theolliviers.com> + + wx build fix. Switch USE_ defines over to the compiler so that they can be + checked by files not including config.h (like WebCorePrefix.h). + + * wtf/Platform.h: + +2009-09-03 Yong Li <yong.li@torchmobile.com> + + Reviewed by David Levin. + + Remove unnecessary dependency on unistd.h + https://bugs.webkit.org/show_bug.cgi?id=28962 + + * runtime/Completion.cpp: + +2009-09-03 Fumitoshi Ukai <ukai@chromium.org> + + Reviewed by Eric Seidel. + + Add strnstr for Linux and Windows in StringExtras.h + https://bugs.webkit.org/show_bug.cgi?id=28901 + + * wtf/StringExtras.h: + (strnstr): + +2009-09-03 Zoltan Horvath <hzoltan@inf.u-szeged.hu> + + Reviewed by Darin Adler. + + Allow custom memory allocation control for JavaScriptCore's HashEntry class + https://bugs.webkit.org/show_bug.cgi?id=27830 + + Inherits HashEntry class from FastAllocBase because it has been + instantiated by 'new' JavaScriptCore/runtime/Lookup.cpp:32. + + * runtime/Lookup.h: + +2009-09-02 Gavin Barraclough <barraclough@apple.com> + + Should crash if JIT code buffer allocation fails. + + https://bugs.webkit.org/show_bug.cgi?id=28926 + <rdar://problem/7031922> + + * jit/ExecutableAllocatorPosix.cpp: + (JSC::ExecutablePool::systemAlloc): + * jit/ExecutableAllocatorWin.cpp: + (JSC::ExecutablePool::systemAlloc): + +2009-09-02 Kevin Ollivier <kevino@theolliviers.com> + + waf build fixes for Windows/MSVC. + + * wscript: + +2009-09-02 Kevin Ollivier <kevino@theolliviers.com> + + Build fix for building on Windows. + + * wtf/ThreadingPthreads.cpp: + +2009-09-02 Norbert Leser <norbert.leser@nokia.com> + + Reviewed by Eric Seidel. + + Use fastMalloc when neither MMAP nor VIRTUALALLOC are enabled + + RegisterFile constructor currently throws #error when both + MMAP and VIRTUALALLOC conditions fail. + On any platform that does not provide these features + (for instance, Symbian), + the fallback should be regular malloc (or fastMalloc). + It is functionally equivalent in this case, even though it may + have certain drawbacks such as lack of dynamic pre-allocation. + + * interpreter/RegisterFile.cpp: + (JSC::RegisterFile::~RegisterFile): + * interpreter/RegisterFile.h: + (JSC::RegisterFile::RegisterFile): + +2009-08-31 Robert Agoston <Agoston.Robert@stud.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Fixed typo. + https://bugs.webkit.org/show_bug.cgi?id=28691 + + * parser/Parser.h: + (JSC::Parser::parse): + +2009-08-27 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + JSON Stringifier does not follow ES5 spec for handling of Number, String and Boolean objects + https://bugs.webkit.org/show_bug.cgi?id=28797 + + Fixed unwrapBoxedPrimitive to do the right thing, which necessitated a couple of new exception + checks, and corrected the logic in gap to correctly convert Number and String objects. + + * runtime/JSONObject.cpp: + (JSC::unwrapBoxedPrimitive): + (JSC::gap): + (JSC::Stringifier::Stringifier): + (JSC::Stringifier::appendStringifiedValue): + +2009-08-27 Oliver Hunt <oliver@apple.com> + + Reviewed by Adam Roben. + + JSON.stringify replacer array does not accept values that are not string primitives. + https://bugs.webkit.org/show_bug.cgi?id=28788 + + Update the JSON stringifier to initialise its replacer array according to the most + recent version of the spec. + + * runtime/Identifier.h: + (JSC::Identifier::from): + * runtime/JSONObject.cpp: + (JSC::Stringifier::Stringifier): + +2009-08-27 Alexey Proskuryakov <ap@apple.com> + + Reviewed by Oliver Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=28753 + <rdar://problem/7173448> Excessive number of threads (and a crash) + + * wtf/Threading.h: (WTF::atomicIncrement): Changed atomicIncrement to match decrement + and return the new value. Also added using directives for these functions, to match + te rest of WTF. + +2009-08-27 Brent Fulgham <bfulgham@webkit.org> + + Reviewed by Adam Roben. + + Link the testapi against CFLite when building the WinCairo port. + + * JavaScriptCore.vcproj/testapi/testapi.vcproj: Add new Release_CFLite + target. Update all targets to inherit from either the + JavaScriptCF.vsprops (Apple target) or the JavaScriptCFLite.vsprops + file (WinCairo target). + * JavaScriptCore.vcproj/testapi/testapiCommon.vsprops: Remove + input file CoreFoundation.lib. This is provided by either the + JavaScriptCF.vsprops or JavaScriptCFLite.vsprops file. + +2009-08-27 Steve Falkenburg <sfalken@apple.com> + + Reviewed by Geoff Garen. + + Fix Windows-specific crash due to missing memory clearing call. + + * runtime/Collector.cpp: + (JSC::Heap::allocateBlock): + +2009-08-27 Brent Fulgham <bfulgham@webkit.org> + + Build fix: JavaScriptCore_debug.def missing some exports. Apple + Windows build does not use this file, so it was not noticed previously. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-08-27 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + x86-64 GTK broken due to code offsets changing, pointers sometimes packed into immediates. + https://bugs.webkit.org/show_bug.cgi?id=28317 + + Missed one, fix part II. + + * assembler/MacroAssemblerX86Common.h: + (JSC::MacroAssemblerX86Common::move): + * assembler/X86Assembler.h: + (JSC::CAN_SIGN_EXTEND_8_32): + +2009-08-27 Oliver Hunt <oliver@apple.com> + + Reviewed by Adam Roben. + + JSON.stringify replacer array does not accept values that are not string primitives. + https://bugs.webkit.org/show_bug.cgi?id=28788 + + Update the JSON stringifier to initialise its replacer array according to the most + recent version of the spec. + + * runtime/Identifier.h: + (JSC::Identifier::from): + * runtime/JSONObject.cpp: + (JSC::Stringifier::Stringifier): + +2009-08-27 Oliver Hunt <oliver@apple.com> + + Reviewed by Alexey Proskuryakov. + + JSON parser accepts trailing comma in array literals + https://bugs.webkit.org/show_bug.cgi?id=28779 + + Update parser to correctly fail if there's a trailing comma. + + * runtime/LiteralParser.cpp: + (JSC::LiteralParser::parse): + +2009-08-26 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + 'this' in JSON.parse reviver is the global object + https://bugs.webkit.org/show_bug.cgi?id=28752 + + This is a technically simple change, we merely update the code for calling + the reviver function to pass the correct this object. Doing so however + exposes the holder to arbitrary mutation by the reviver function so it is + necessary for us to now guard all property accesses against the possibility + of failure. + + * runtime/JSArray.h: + JSON needs to delete a property from the array, so we friend its + Walker class so that we can make a non-virtual call to the arrays + delete and getOwnPropertySlot methods. + * runtime/JSONObject.cpp: + (JSC::Walker::callReviver): + We need to pass the correct this object + (JSC::Walker::walk): + Update calls to callReviver, and update property logic logic + to correctly handle the holder being mutated by the reviver + function. + +2009-08-26 Alice Liu <alice.liu@apple.com> + + Windows build fix: added some exported symbols + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-08-26 Geoffrey Garen <ggaren@apple.com> + + Windows build fix: Removed some exported symbols that no longer exist. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-08-26 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Olliejver Hunt. + + x86-64 GTK broken due to code offsets changing, pointers sometimes packed into immediates. + https://bugs.webkit.org/show_bug.cgi?id=28317 + + We rely on a slightly OS X specific behaviour, that x86-64 applications have a 4Gb zero page, + so pointers are never representable as a 32-bit integer, and always have to be represented by + a separate immediate load instruction, rather than within the immediate field of an arithmetic + or memory operation. + + We explicitly check for a couple of cases where a value might be representable in 32-bit, but + these probably never kick in on Mac OS, and only kick in to hose GTK. Deleting these does not + show a performance degradation on SunSpider. Remove. + + * assembler/MacroAssemblerX86_64.h: + (JSC::MacroAssemblerX86_64::storePtr): + (JSC::MacroAssemblerX86_64::branchPtr): + +2009-08-26 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + A bit of Collector refatoring. + + SunSpider says no change. v8 says 1.003x faster (1.02x faster on splay). + + * JavaScriptCore.exp: + + * runtime/JSCell.cpp: + (JSC::JSCell::toPrimitive): + (JSC::JSCell::getPrimitiveNumber): + (JSC::JSCell::toBoolean): + (JSC::JSCell::toNumber): + (JSC::JSCell::toString): + (JSC::JSCell::toObject): Removed pure virtual functions from + JSCell, so the collector can construct one. This allowed + me to remove a bunch of ASSERT_NOT_REACHED throughout the + code, too. + + * runtime/JSCell.h: + (JSC::JSCell::JSCell): ditto + (JSC::Heap::heap): Inlined this function because it's trivial. + + * JavaScriptCore.exp: + + * runtime/Collector.cpp: + (JSC::Heap::destroy): + (JSC::Heap::allocateBlock): + (JSC::Heap::freeBlock): + (JSC::Heap::freeBlocks): Renamed freeHeap to freeBlocks, since + it doesn't actually free the Heap object. + (JSC::Heap::heapAllocate): + (JSC::Heap::sweep): + * runtime/Collector.h: Refactored block allocation and destruction + into helper functions. + + * runtime/GetterSetter.cpp: + * runtime/JSAPIValueWrapper.cpp: + * runtime/JSPropertyNameIterator.cpp: Removed dummy implementations + of pure virtual functions. (See above.) + +=== End re-roll-in of r47738:47740 with Windows crash fixed === + +2009-08-26 Geoffrey Garen <ggaren@apple.com> + + Build fix: start out with a 32-bit value to avoid a shortening warning. + + * runtime/Collector.cpp: + (JSC::Heap::sweep): + +2009-08-24 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Oliver Hunt. + + Substantially reduced VM thrash in the GC heap. + + 1.08x faster on v8 (1.60x faster on v8-splay). + + 1.40x faster on bench-alloc-nonretained. + + 1.90x faster on bench-alloc-retained. + + SunSpider says no change. + + * runtime/Collector.cpp: + (JSC::Heap::heapAllocate): Fixed a long-standing bug: update a few local + variables unconditionally after calling collect(), since they may be used + even if we don't "goto scan". (In the bug I saw, usedBlocks got out of + sync with heap.usedBlocks). + (JSC::Heap::sweep): Keep enough free heap space to accomodate + the number of objects we'll allocate before the next GC, plus 25%, for + good measure. + * runtime/Collector.h: Bumped the block size to 256k. This seems to give + the best cache performance, and it prevents us from initiating lots of + VM traffic to recover very small chunks of memory. + +=== Begin re-roll-in of r47738:47740 with Windows crash fixed === + +2009-08-25 Drew Wilson <atwilson@google.com> + + Reviewed by David Levin. + + postMessage() spec now supports sending arrays of ports + https://bugs.webkit.org/show_bug.cgi?id=26902 + + Added OwnPtr to VectorTraits so we can store OwnPtrs in Vectors. + + * wtf/VectorTraits.h: + +2009-08-26 Xan Lopez <xlopez@igalia.com> + + Rubber-stamped by Gustavo Noronha. + + Remove duplicated files from file list. + + * GNUmakefile.am: + +2009-08-26 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fix). + + More export fixes. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-08-26 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fix). + + Hopefully fix all the exports from JSC on windows + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-08-26 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Build fixes). + + Forgot I added files to JavaScriptCore. + + * GNUmakefile.am: + * JavaScriptCore.gypi: + * JavaScriptCore.pri: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: + * JavaScriptCoreSources.bkl: + +2009-08-25 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + [ES5] Implement getOwnPropertyDescriptor + https://bugs.webkit.org/show_bug.cgi?id=28724 + + Implement the core runtime support for getOwnPropertyDescriptor. + This adds a virtual getOwnPropertyDescriptor method to every class + that implements getOwnPropertySlot that shadows the behaviour of + getOwnPropertySlot. The alternative would be to make getOwnPropertySlot + (or PropertySlots in general) provide property attribute information, + but quick testing showed this to be a regression. + + * JavaScriptCore.exp: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/Arguments.cpp: + (JSC::Arguments::getOwnPropertyDescriptor): + * runtime/Arguments.h: + * runtime/ArrayPrototype.cpp: + (JSC::ArrayPrototype::getOwnPropertyDescriptor): + * runtime/ArrayPrototype.h: + * runtime/CommonIdentifiers.h: + * runtime/DatePrototype.cpp: + (JSC::DatePrototype::getOwnPropertyDescriptor): + * runtime/DatePrototype.h: + * runtime/JSArray.cpp: + (JSC::JSArray::getOwnPropertyDescriptor): + * runtime/JSArray.h: + * runtime/JSByteArray.cpp: + (JSC::JSByteArray::getOwnPropertyDescriptor): + * runtime/JSByteArray.h: + * runtime/JSFunction.cpp: + (JSC::JSFunction::getOwnPropertyDescriptor): + * runtime/JSFunction.h: + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::getOwnPropertyDescriptor): + * runtime/JSNotAnObject.cpp: + (JSC::JSNotAnObject::getOwnPropertyDescriptor): + * runtime/JSNotAnObject.h: + * runtime/JSONObject.cpp: + (JSC::JSONObject::getOwnPropertySlot): + (JSC::JSONObject::getOwnPropertyDescriptor): + * runtime/JSONObject.h: + * runtime/JSObject.cpp: + (JSC::JSObject::getOwnPropertyDescriptor): + (JSC::JSObject::getPropertyDescriptor): + * runtime/JSObject.h: + * runtime/JSString.cpp: + (JSC::JSString::getStringPropertyDescriptor): + (JSC::JSString::getOwnPropertyDescriptor): + * runtime/JSString.h: + * runtime/JSVariableObject.cpp: + (JSC::JSVariableObject::symbolTableGet): + * runtime/JSVariableObject.h: + * runtime/Lookup.h: + (JSC::getStaticPropertyDescriptor): + (JSC::getStaticFunctionDescriptor): + (JSC::getStaticValueDescriptor): + Add property descriptor equivalents of the lookup + table access functions + + * runtime/MathObject.cpp: + (JSC::MathObject::getOwnPropertySlot): + (JSC::MathObject::getOwnPropertyDescriptor): + * runtime/MathObject.h: + * runtime/NumberConstructor.cpp: + (JSC::NumberConstructor::getOwnPropertyDescriptor): + * runtime/NumberConstructor.h: + * runtime/ObjectConstructor.cpp: + (JSC::ObjectConstructor::ObjectConstructor): + (JSC::objectConstructorGetOwnPropertyDescriptor): + * runtime/PropertyDescriptor.cpp: Added. + (JSC::PropertyDescriptor::writable): + (JSC::PropertyDescriptor::enumerable): + (JSC::PropertyDescriptor::configurable): + (JSC::PropertyDescriptor::hasAccessors): + (JSC::PropertyDescriptor::setUndefined): + (JSC::PropertyDescriptor::getter): + (JSC::PropertyDescriptor::setter): + (JSC::PropertyDescriptor::setDescriptor): + (JSC::PropertyDescriptor::setAccessorDescriptor): + * runtime/PropertyDescriptor.h: Added. + (JSC::PropertyDescriptor::PropertyDescriptor): + (JSC::PropertyDescriptor::attributes): + (JSC::PropertyDescriptor::isValid): + (JSC::PropertyDescriptor::value): + * runtime/RegExpConstructor.cpp: + (JSC::RegExpConstructor::getOwnPropertyDescriptor): + * runtime/RegExpConstructor.h: + * runtime/RegExpMatchesArray.h: + (JSC::RegExpMatchesArray::getOwnPropertyDescriptor): + * runtime/RegExpObject.cpp: + (JSC::RegExpObject::getOwnPropertyDescriptor): + * runtime/RegExpObject.h: + * runtime/StringObject.cpp: + (JSC::StringObject::getOwnPropertyDescriptor): + * runtime/StringObject.h: + * runtime/StringPrototype.cpp: + (JSC::StringPrototype::getOwnPropertyDescriptor): + * runtime/StringPrototype.h: + +2009-08-24 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Darin Adler. + + How many copies of the parameters do you need? + https://bugs.webkit.org/show_bug.cgi?id=28701 + + The function parameters in JSC get copied a lot - and unnecessarily so. + + Originally this happened due to duplicating FunctionBodyNodes on recompilation, + though the problem has been exacerbated by copying the parameters from the + original function body onto the executable, then back onto the real body that + will be generated (this happens on every function). And this is all made worse + since the data structures in question are a little ugly - C style arrays of C++ + objects containing ref counts, so they need a full copy-construct (rather than + a simple memcpy). + + This can all be greatly simplified by just punting the parameters off into + their own ref-counted object, and forgoing all the copying. + + ~no performance change, possible slight progression. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::makeFunction): + * parser/Nodes.cpp: + (JSC::FunctionParameters::FunctionParameters): + (JSC::FunctionBodyNode::FunctionBodyNode): + (JSC::FunctionBodyNode::finishParsing): + * parser/Nodes.h: + (JSC::FunctionBodyNode::parameters): + (JSC::FunctionBodyNode::parameterCount): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::~FunctionExecutable): + (JSC::FunctionExecutable::compile): + (JSC::FunctionExecutable::reparseExceptionInfo): + (JSC::FunctionExecutable::fromGlobalCode): + (JSC::FunctionExecutable::paramString): + * runtime/Executable.h: + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::FunctionExecutable::parameterCount): + +2009-08-25 Brent Fulgham <bfulgham@webkit.org> + + Reviewed by NOBODY (Buildfix). + + * JavaScriptCore.vcproj/jsc/jsc.vcproj: Add Debug_CFLite target + that inherits from the debug_wincairo property sheet and therefore + links to the proper debug library. + * JavaScriptCore.vcproj/testapi/testapi.vcproj: Add Debug_CFLite target + that inherits from the debug_wincairo property sheet and therefore + links to the proper debug library. + +2009-08-25 Chris Marrin <cmarrin@apple.com> + + Reviewed by Simon Fraser. + + Export tryFastMalloc for Canvas3D work + https://bugs.webkit.org/show_bug.cgi?id=28018 + + * JavaScriptCore.exp: + +2009-08-25 David Levin <levin@chromium.org> + + Reviewed by Adam Roben. + + PLATFORM(CFNETWORK) should be USE(CFNETWORK). + https://bugs.webkit.org/show_bug.cgi?id=28713 + + * wtf/Platform.h: Added a #define to catch this issue in the + future. The define would generate an error on gcc without the + space in the expansion, but Visual C++ needs the space to cause an error. + +2009-08-24 Brent Fulgham <bfulgham@webkit.org> + + Reviewed by Steve Falkenburg. + + Revise CFLite Debug build to emit DLL's with _debug label. + https://bugs.webkit.org/show_bug.cgi?id=28695. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj: Modify + Cairo debug build to inherit from new debug_cairo property sheet. + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCFLite.vsprops: + Modify to look for debug CFLite when in debug build. + +2009-08-24 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Adler & Darin Hunt. + + https://bugs.webkit.org/show_bug.cgi?id=28691 + Do not retain ScopeNodes outside of parsing + + There is now no need for these to exist outside of parsing - their use in the runtime is replaced by Executable types. + + * bytecode/EvalCodeCache.h: + (JSC::EvalCodeCache::get): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitNewFunction): + (JSC::BytecodeGenerator::emitNewFunctionExpression): + * bytecompiler/BytecodeGenerator.h: + (JSC::BytecodeGenerator::makeFunction): + * debugger/Debugger.cpp: + (JSC::Debugger::recompileAllJSFunctions): + (JSC::evaluateInGlobalCallFrame): + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::evaluate): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + (JSC::Interpreter::prepareForRepeatCall): + (JSC::Interpreter::privateExecute): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * parser/Nodes.cpp: + (JSC::ScopeNodeData::ScopeNodeData): + (JSC::ProgramNode::create): + (JSC::EvalNode::create): + (JSC::FunctionBodyNode::create): + * parser/Nodes.h: + (JSC::ScopeNode::adoptData): + (JSC::FunctionBodyNode::parameterCount): + * parser/Parser.cpp: + * parser/Parser.h: + (JSC::Parser::arena): + (JSC::Parser::Parser): + (JSC::Parser::parse): + * runtime/ArrayPrototype.cpp: + (JSC::isNumericCompareFunction): + (JSC::arrayProtoFuncSort): + * runtime/Completion.cpp: + (JSC::checkSyntax): + (JSC::evaluate): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::~FunctionExecutable): + (JSC::EvalExecutable::compile): + (JSC::ProgramExecutable::checkSyntax): + (JSC::ProgramExecutable::compile): + (JSC::FunctionExecutable::compile): + (JSC::EvalExecutable::generateJITCode): + (JSC::ProgramExecutable::generateJITCode): + (JSC::FunctionExecutable::generateJITCode): + (JSC::FunctionExecutable::reparseExceptionInfo): + (JSC::EvalExecutable::reparseExceptionInfo): + (JSC::FunctionExecutable::recompile): + (JSC::FunctionExecutable::fromGlobalCode): + (JSC::FunctionExecutable::copyParameters): + (JSC::FunctionExecutable::paramString): + * runtime/Executable.h: + (JSC::ScriptExecutable::ScriptExecutable): + (JSC::ScriptExecutable::sourceID): + (JSC::ScriptExecutable::sourceURL): + (JSC::ScriptExecutable::lineNo): + (JSC::ScriptExecutable::lastLine): + (JSC::ScriptExecutable::usesEval): + (JSC::ScriptExecutable::usesArguments): + (JSC::ScriptExecutable::needsActivation): + (JSC::ScriptExecutable::recordParse): + (JSC::EvalExecutable::bytecode): + (JSC::EvalExecutable::jitCode): + (JSC::ProgramExecutable::bytecode): + (JSC::ProgramExecutable::reparseExceptionInfo): + (JSC::ProgramExecutable::jitCode): + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::FunctionExecutable::make): + (JSC::FunctionExecutable::bytecode): + (JSC::FunctionExecutable::isGenerated): + (JSC::FunctionExecutable::name): + (JSC::FunctionExecutable::parameterCount): + (JSC::FunctionExecutable::jitCode): + * runtime/FunctionConstructor.cpp: + (JSC::constructFunction): + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::numericCompareFunction): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncEval): + +2009-08-24 Darin Adler <darin@apple.com> + + * runtime/ObjectPrototype.cpp: + (JSC::ObjectPrototype::put): Landed revised version I had tested but forgot + to land. Leave out the branch, since we don't need one. + +2009-08-24 Darin Adler <darin@apple.com> + + Reviewed by Geoff Garen. + + Array index miss case creates a string every time + https://bugs.webkit.org/show_bug.cgi?id=28664 + + SunSpider test results I saw: + + 0.5% faster overall + 1% faster on crypto-aes + 20% faster on crypto-md5 + 13% faster on crypto-sha1 + + * runtime/ObjectPrototype.cpp: + (JSC::ObjectPrototype::ObjectPrototype): Initialize m_hasNoPropertiesWithUInt32Names + to true. + (JSC::ObjectPrototype::put): Clearly m_hasNoPropertiesWithUInt32Names if the new + property has a name that is the string form of a UInt32. + (JSC::ObjectPrototype::getOwnPropertySlot): Don't call JSObject::getOwnPropertySlot + if m_hasNoPropertiesWithUInt32Names is true, and it is highly likely to be true. + + * runtime/ObjectPrototype.h: Added declarations for the above. + +2009-08-24 Gustavo Noronha Silva <gustavo.noronha@collabora.co.uk> + + Unreviewed. Fix a typo in my distcheck build fix. + + * GNUmakefile.am: + +2009-08-23 Gustavo Noronha Silva <gns@gnome.org> + + Unreviewed build fix for make distcheck. + + * GNUmakefile.am: Added files required for the build. + +2009-08-22 Maciej Stachowiak <mjs@apple.com> + + Reviewed by Mark Rowe. + + REGRESSION(r47639-r47660): Webkit crashes on launch on PowerPC + https://bugs.webkit.org/show_bug.cgi?id=28655 + + * runtime/JSFunction.cpp: + (JSC::JSFunction::JSFunction): Initialize properly with a VPtrHackExecutable. + * wtf/Platform.h: + +2009-08-22 Darin Adler <darin@apple.com> + + Fix storage leak from syntax tree arena allocation patch. + + * parser/Nodes.h: CommaNode needs to inherit from ParserArenaDeletable + because it has a vector. + +2009-08-21 Darin Adler <darin@apple.com> + + Fix Qt build. + + * parser/Nodes.cpp: + (JSC::ScopeNodeData::ScopeNodeData): Made non-inline again. + This is used outside Nodes.cpp so can't be inline unless + it is in the header. + +2009-08-21 Darin Adler <darin@apple.com> + + Two loose ends from the last commit. + + * JavaScriptCore.xcodeproj/project.pbxproj: Made ParserArena.h + and create_hash_table project-internal instead of "private". + * runtime/Executable.h: Removed accidentally-added constructor. + +2009-08-21 Darin Adler <darin@apple.com> + + Reviewed by Gavin Barraclough. + + Syntax tree nodes should use arena allocation + https://bugs.webkit.org/show_bug.cgi?id=25674 + + Use an actual arena now. 0.6% speedup on SunSpider. + + New and improved with 100% less leaking of the universe. + + * JavaScriptCore.exp: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + Removed all exports involving the class FunctionBodyNode, which no + longer needs to be used outside JavaScriptCore. + + * JavaScriptCore.xcodeproj/project.pbxproj: Made Nodes.h and + Executable.h project-internal instead of "private". + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): Updated since VarStack + contains const Identifier* now. + + * parser/Grammar.y: Made identifiers from the lexer be const + Identifier* and updated since VarStack contains const Identifier* now. + + * parser/Lexer.cpp: + (JSC::Lexer::setCode): Pass in ParserArena, used for identifiers. + (JSC::Lexer::makeIdentifier): Changed return type to const Identifier* + and changed to call ParserArena. + (JSC::Lexer::clear): Removed the code to manage m_identifiers and + added code to set m_arena to 0. + * parser/Lexer.h: Updated for changes above. + + * parser/NodeConstructors.h: + (JSC::ParserArenaFreeable::operator new): Added. Calls allocateFreeable + on the arena. + (JSC::ParserArenaDeletable::operator new): Changed to call the + allocateDeletable function on the arena instead of deleteWithArena. + (JSC::PropertyNode::PropertyNode): Added new constructor that makes + numeric identifiers. Some day we might want to optimize this for + integers so it doesn't create a string for each one. + (JSC::ContinueNode::ContinueNode): Initialize m_ident to nullIdentifier + since it's now a const Identifier& so it can't be left uninitialized. + (JSC::BreakNode::BreakNode): Ditto. + (JSC::CaseClauseNode::CaseClauseNode): Updated to use SourceElements* + to keep track of the statements rather than a separate statement vector. + (JSC::BlockNode::BlockNode): Ditto. + (JSC::ForInNode::ForInNode): Initialize m_ident to nullIdentifier. + + * parser/Nodes.cpp: Moved the comment explaining emitBytecode in here. + It seemed strangely out of place in the header. + (JSC::ThrowableExpressionData::emitThrowError): Added an overload for + UString as well as Identifier. + (JSC::SourceElements::singleStatement): Added. + (JSC::SourceElements::lastStatement): Added. + (JSC::RegExpNode::emitBytecode): Changed the throwError code to use + the substitution mechanism instead of doing a string append. + (JSC::SourceElements::emitBytecode): Added. Replaces the old + statementListEmitCode function, since we now keep the SourceElements + objects around. + (JSC::BlockNode::lastStatement): Added. + (JSC::BlockNode::emitBytecode): Changed to use emitBytecode instead of + statementListEmitCode. + (JSC::CaseClauseNode::emitBytecode): Added. + (JSC::CaseBlockNode::emitBytecodeForBlock): Changed to use emitBytecode + instead of statementListEmitCode. + (JSC::ScopeNodeData::ScopeNodeData): Changed to store the + SourceElements* instead of using releaseContentsIntoVector. + (JSC::ScopeNode::emitStatementsBytecode): Added. + (JSC::ScopeNode::singleStatement): Added. + (JSC::ProgramNode::emitBytecode): Call emitStatementsBytecode instead + of statementListEmitCode. + (JSC::EvalNode::emitBytecode): Ditto. + (JSC::FunctionBodyNode::emitBytecode): Call emitStatementsBytecode + insetad of statementListEmitCode and check for the return node using + the new functions. + + * parser/Nodes.h: Changed VarStack to store const Identifier* instead + of Identifier and rely on the arena to control lifetime. Added a new + ParserArenaFreeable class. Made ParserArenaDeletable inherit from + FastAllocBase instead of having its own operator new. Base the Node + class on ParserArenaFreeable. Changed the various Node classes + to use const Identifier& instead of Identifier to avoid the need to + call their destructors and allow them to function as "freeable" in the + arena. Removed extraneous JSC_FAST_CALL on definitions of inline functions. + Changed ElementNode, PropertyNode, ArgumentsNode, ParameterNode, + CaseClauseNode, ClauseListNode, and CaseBlockNode to use ParserArenaFreeable + as a base class since they do not descend from Node. Eliminated the + StatementVector type and instead have various classes use SourceElements* + instead of StatementVector. This prevents those classes from having to + use ParserArenaDeletable to make sure the vector destructor is called. + + * parser/Parser.cpp: + (JSC::Parser::parse): Pass the arena to the lexer. + + * parser/Parser.h: Added an include of ParserArena.h, which is no longer + included by Nodes.h. + (JSC::Parser::parseFunctionFromGlobalCode): Changed to use the + singleStatement function, since there is no longer any children function. + Removed some unneeded use of RefPtr. + + * parser/ParserArena.cpp: + (JSC::ParserArena::ParserArena): Added. Initializes the new members, + m_freeableMemory, m_freeablePoolEnd, and m_identifiers. + (JSC::ParserArena::freeablePool): Added. Computes the pool pointer, + since we store only the current pointer and the end of pool pointer. + (JSC::ParserArena::deallocateObjects): Added. Contains the common + memory-deallocation logic used by both the destructor and the + reset function. + (JSC::ParserArena::~ParserArena): Changed to call deallocateObjects. + (JSC::ParserArena::reset): Ditto. Also added code to zero out the + new structures, and switched to use clear() instead of shrink(0) since + we don't really reuse arenas. + (JSC::ParserArena::makeNumericIdentifier): Added. + (JSC::ParserArena::allocateFreeablePool): Added. Used when the pool + is empty. + (JSC::ParserArena::isEmpty): Added. No longer inline, which is fine + since this is used only for assertions at the moment. + (JSC::ParserArena::derefWithArena): Make non-inline. + + * parser/ParserArena.h: Added an actual arena of "freeable" objects, + ones that don't need destructors to be called. Also added a separate + IdentifierArena object, a segmented vector of identifiers that used + to be in the Lexer. + + * runtime/Executable.h: Moved the definition of the + FunctionExecutable::make function here. It can't go in JSFunction.h + since that header has to be used outside JavaScriptCore and so can't + include this, which includes Nodes.h. The function could be moved + elswhere if we don't want to include JSFunction.h in this header, but + for now this seems to be the best place. + + * runtime/JSFunction.h: Removed the include of Executable.h and + definition of the FunctionExecutable::make function. + + * wtf/FastMalloc.cpp: Fixed an incorrect comment. + +2009-08-21 Mark Rowe <mrowe@apple.com> + + Fix the non-JIT build. + + * runtime/Executable.cpp: + * runtime/Executable.h: + +2009-08-21 Gavin Barraclough <barraclough@apple.com> + + Speculative QuickTime build fix. + + * runtime/JSArray.cpp: + +2009-08-21 Gavin Barraclough <barraclough@apple.com> + + Speculative QT build fix. + + * runtime/StringPrototype.cpp: + +2009-08-21 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Restructure Executable types so that host functions do not hold a FunctionExecutable. + https://bugs.webkit.org/show_bug.cgi?id=28621 + + All JSFunction objects have a pointer to an Executable*. This is currently always a + FunctionExecutable, however this has a couple of drawbacks. Host functions do not + store a range of information that the FunctionExecutable provides (source, name, + CodeBlock & information presently held on the FunctionBodyNode). + + [ * nearly all... see below! ] + + Instead, make JSFunctions hold a pointer to an ExecutableBase, move fields specific + to JS sourced executable types (source, node) into a new subclass (ScriptExecutable), + and create a new NativeExecutable type. We now provide a new method in JSFunction + to access & downcast to FunctionExecutable, but in doing so we can make an early + check (with an ASSERT) to ensure that the Executable read from a function will only + be treated as a FunctionExecutable (and thus the JS sepcific fields will only be + accessed) if the JSFunction is not a host function. + + There is one JSFunction that currently does not have an Executable, which is the + object created to allow us to read out the vtable pointer. By making this change + we can also add a new Executable type fror this object (VPtrHackExecutable). + Since this means that really all JSFunctions have an Executable we no longer have + to null-check m_executable before us it - particularly in isHostFunction(). + + This patch removes CacheableEvalExecutable, since all subclasses of ExecutableBase + can now be ref-counted - since both JSFunction holds (and ref-counts) an ExecutableBase + that might be a FunctionExecutable or a NativeExecutable. This does now mean that all + ProgramExecutables and EvalExecutables (unnecessarily) provide an interface to be + ref-counted, however this seems less-bad than host functions unnecessarily providing + interface to access non-host specific information. + + The class hierarcy has changed from this: + + - ExecutableBase + - ProgramExecutable + - EvalExecutable + - CacheableEvalExecutable (also RefCounted by multiple-inheritance) + - FunctionExecutable (also RefCounted by multiple-inheritance, 'special' FunctionExecutable also used for host functions) + + To this: + + - RefCounted + - ExecutableBase + - NativeExecutable + - VPtrHackExecutable + - ScriptExecutable + - ProgramExecutable + - EvalExecutable + - FunctionExecutable + + This patch speeds up sunspidey by a couple of ms (presumably due to the changes to isHostFunction()). + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::ownerExecutable): + (JSC::GlobalCodeBlock::GlobalCodeBlock): + * bytecode/EvalCodeCache.h: + (JSC::EvalCodeCache::get): + * debugger/Debugger.cpp: + (JSC::Debugger::recompileAllJSFunctions): + * interpreter/CachedCall.h: + (JSC::CachedCall::CachedCall): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::callEval): + (JSC::Interpreter::privateExecute): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * profiler/Profiler.cpp: + (JSC::createCallIdentifierFromFunctionImp): + * runtime/Arguments.h: + (JSC::Arguments::getArgumentsData): + (JSC::Arguments::Arguments): + * runtime/Executable.cpp: + (JSC::NativeExecutable::~NativeExecutable): + (JSC::VPtrHackExecutable::~VPtrHackExecutable): + * runtime/Executable.h: + (JSC::ExecutableBase::ExecutableBase): + (JSC::ExecutableBase::~ExecutableBase): + (JSC::ExecutableBase::isHostFunction): + (JSC::NativeExecutable::NativeExecutable): + (JSC::VPtrHackExecutable::VPtrHackExecutable): + (JSC::ScriptExecutable::ScriptExecutable): + (JSC::ScriptExecutable::source): + (JSC::ScriptExecutable::sourceID): + (JSC::ScriptExecutable::sourceURL): + (JSC::ScriptExecutable::lineNo): + (JSC::ScriptExecutable::lastLine): + (JSC::ScriptExecutable::usesEval): + (JSC::ScriptExecutable::usesArguments): + (JSC::ScriptExecutable::needsActivation): + (JSC::EvalExecutable::EvalExecutable): + (JSC::EvalExecutable::create): + (JSC::ProgramExecutable::ProgramExecutable): + (JSC::FunctionExecutable::FunctionExecutable): + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncToString): + * runtime/JSFunction.cpp: + (JSC::JSFunction::JSFunction): + (JSC::JSFunction::~JSFunction): + (JSC::JSFunction::markChildren): + (JSC::JSFunction::getCallData): + (JSC::JSFunction::call): + (JSC::JSFunction::lengthGetter): + (JSC::JSFunction::getConstructData): + (JSC::JSFunction::construct): + * runtime/JSFunction.h: + (JSC::JSFunction::executable): + (JSC::JSFunction::jsExecutable): + (JSC::JSFunction::isHostFunction): + +2009-08-20 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Browser hangs on opening Web Inspector. + https://bugs.webkit.org/show_bug.cgi?id=28438 + + Code generation needs to be able to walk the entire scopechain in some + cases, however the symbol table used by activations was a member of the + codeblock. Following recompilation this may no longer exist, leading + to a crash or hang on lookup. + + We fix this by introducing a refcounted SymbolTable subclass, SharedSymbolTable, + for the CodeBlocks used by function code. This allows activations to + maintain ownership of a copy of the symbol table even after recompilation so + they can continue to work. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::symbolTable): + (JSC::CodeBlock::sharedSymbolTable): + (JSC::GlobalCodeBlock::GlobalCodeBlock): + (JSC::FunctionCodeBlock::FunctionCodeBlock): + (JSC::FunctionCodeBlock::~FunctionCodeBlock): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::retrieveArguments): + * runtime/Executable.cpp: + (JSC::EvalExecutable::generateBytecode): + (JSC::FunctionExecutable::generateBytecode): + (JSC::FunctionExecutable::reparseExceptionInfo): + (JSC::EvalExecutable::reparseExceptionInfo): + * runtime/JSActivation.h: + (JSC::JSActivation::JSActivationData::JSActivationData): + (JSC::JSActivation::JSActivationData::~JSActivationData): + * runtime/SymbolTable.h: + +2009-08-20 Xan Lopez <xlopez@igalia.com> + + Add new file to GTK+ build. + + * GNUmakefile.am: + +2009-08-20 Geoffrey Garen <ggaren@apple.com> + + Reviewed by Maciej Stachowiak. + + Added a number => string cache. + + 1.07x faster on v8 (1.7x faster on v8-splay). + 1.004x faster on SunSpider. + + * runtime/JSCell.h: Moved JSValue::toString to JSString.h. + * runtime/JSGlobalData.h: Holds the cache. + * runtime/JSNumberCell.cpp: + (JSC::JSNumberCell::toString): + (JSC::JSNumberCell::toThisString): Removed -0 special case. + UString handles this now, since too many clients were + special-casing it. + + * runtime/JSString.h: + (JSC::JSValue::toString): Use the cache when converting + an int or double to string. + + * runtime/Operations.h: + (JSC::concatenateStrings): Call toString to take advantage + of the cache. + + * runtime/SmallStrings.h: + (JSC::NumericStrings::add): + (JSC::NumericStrings::lookup): The cache. + + * runtime/UString.cpp: + (JSC::UString::from): Added -0 special case mentioned above. + Removed appendNumeric because it's mutually exclusive with the + cache. + +2009-08-20 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + REGRESSION: fast/profiler/call.html is crashing occasionally + https://bugs.webkit.org/show_bug.cgi?id=28476 + + Using the codeblock for information about how many parameters and + locals a function has is unsafe in certain circumstances. The + basic scenario is all function code being cleared in response to + the debugger or profiler being enabled, and then an activation is + marked before its associated function is re-executed. + + To deal with this scenario we store the variable count of a function + directly in the FunctionExecutable, and then use that information. + + * runtime/Arguments.h: + (JSC::Arguments::getArgumentsData): + * runtime/Executable.cpp: + (JSC::FunctionExecutable::generateBytecode): + * runtime/Executable.h: + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::FunctionExecutable::variableCount): + * runtime/JSActivation.cpp: + (JSC::JSActivation::markChildren): + +2009-08-20 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Numbering of arguments to emitGetJITStubArg/emitPutJITStubArg incorrect + <bug lost in the great bug disasteroony of 08/20/09!> + + The argumentNumber argument to emitGetJITStubArg/emitPutJITStubArg should match + the argument number used within the stub functions in JITStubs.cpp, but it doesn't. + + Firstly, all the numbers changed when we added a void* 'reserved' as the first slot + (rather than leaving argument 0 unused), and secondly in 32_64 builds the index to + peek/poke needs to be multiplies by 2 (since the argument to peek/poke is a number + of machine words, and on 32_64 build the argument slots to stub functions are two + words wide). + + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileOpCallSetupArgs): + (JSC::JIT::compileOpConstructSetupArgs): + (JSC::JIT::compileOpCallVarargsSetupArgs): + (JSC::JIT::compileOpCall): + * jit/JITInlineMethods.h: + (JSC::JIT::emitPutJITStubArg): + (JSC::JIT::emitPutJITStubArgConstant): + (JSC::JIT::emitGetJITStubArg): + (JSC::JIT::emitPutJITStubArgFromVirtualRegister): + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::privateCompilePutByIdTransition): + +2009-08-20 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + REGRESSION: significant slowdown on Celtic Kane "AJAX declaration" subtest + https://bugs.webkit.org/show_bug.cgi?id=28332 + + Follow up style fixes that were missed in review. + + * runtime/Structure.cpp: + (JSC::Structure::hasTransition): + * runtime/Structure.h: + (JSC::Structure::get): + (JSC::StructureTransitionTable::contains): + * runtime/StructureTransitionTable.h: + (JSC::StructureTransitionTable::add): + +2009-08-20 Oliver Hunt <oliver@apple.com> + + Add new exports to windows jsc build + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-08-20 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + REGRESSION: significant slowdown on Celtic Kane "AJAX declaration" subtest + https://bugs.webkit.org/show_bug.cgi?id=28332 + + The method check optimisation made transitions aware of the value being + assigned when a transition was assigning a function. This had the side + effect of making every assignment of a function expression result in a + new transition, and thus a new Structure. The net result of this is that + the common JS idiom of + + function MyObject() { + this.myFunction = function(...){...}; + } + new MyObject(); + + Will produce a unique structure on every iteration, meaning that all + caching is defeated and there is a significant amount of structure churn. + + The fix is to return the transition to its original form where it is + keyed off a property name + attributes tuple, but have each transition + support an optional transition on a specific value. + + * JavaScriptCore.exp: + * runtime/JSObject.h: + (JSC::JSObject::putDirectInternal): + * runtime/Structure.cpp: + (JSC::Structure::~Structure): + (JSC::Structure::addPropertyTransitionToExistingStructure): + (JSC::Structure::addPropertyTransition): + (JSC::Structure::hasTransition): + * runtime/Structure.h: + (JSC::Structure::transitionedFor): + (JSC::Structure::hasTransition): + (JSC::Structure::): + (JSC::StructureTransitionTable::contains): + (JSC::StructureTransitionTable::get): + * runtime/StructureTransitionTable.h: + (JSC::StructureTransitionTableHashTraits::emptyValue): + (JSC::StructureTransitionTable::hasTransition): + (JSC::StructureTransitionTable::remove): + (JSC::StructureTransitionTable::add): + +2009-08-20 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Remove FunctionCodeBlock. + https://bugs.webkit.org/show_bug.cgi?id=28502 + + These only exist to allow JIT code to dereference properties off the + CodeBlock for any callee, regardless of whether it is a host function. + + Instead just use the FunctionExecutable. Copy the m_parameters field + from the CodeBlock into the Executable, and use this to distinguish + between host functions, functions that have been bytecompiled, and + functions that have not. + + m_parameters is moved to ExecutableBase rather than FunctionExecutable + so that (as a separate change) we can move make a separate class of + executable for host code, which is not devived from FunctionExecutable + (host code does not feature any of the properties that normal executable + do and will provide, such as source, attributes, and a parsed name). + + 1% win on v8 tests, 0.5% on sunspider. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::derefStructures): + (JSC::CodeBlock::refStructures): + (JSC::CodeBlock::reparseForExceptionInfoIfNecessary): + (JSC::CodeBlock::handlerForBytecodeOffset): + (JSC::CodeBlock::lineNumberForBytecodeOffset): + (JSC::CodeBlock::expressionRangeForBytecodeOffset): + (JSC::CodeBlock::getByIdExceptionInfoForBytecodeOffset): + (JSC::CodeBlock::functionRegisterForBytecodeOffset): + (JSC::CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset): + (JSC::CodeBlock::hasGlobalResolveInfoAtBytecodeOffset): + * bytecode/CodeBlock.h: + (JSC::): + (JSC::CodeBlock::source): + (JSC::CodeBlock::sourceOffset): + (JSC::CodeBlock::evalCodeCache): + (JSC::CodeBlock::createRareDataIfNecessary): + + remove NativeCodeBlocks and the NativeCode code type. + + * jit/JIT.cpp: + (JSC::JIT::linkCall): + + Revert to previous behaviour (as currently still commented!) that Hhost functions have a null codeblock. + + * jit/JITCall.cpp: + (JSC::JIT::compileOpCallInitializeCallFrame): + (JSC::JIT::compileOpCallSetupArgs): + (JSC::JIT::compileOpCallVarargsSetupArgs): + (JSC::JIT::compileOpConstructSetupArgs): + (JSC::JIT::compileOpCallVarargs): + (JSC::JIT::compileOpCall): + (JSC::JIT::compileOpCallSlowCase): + + Bring the 32_64 & non-32_64 JITs into line with each other, callee in regT0. + + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + + Rewrite call trampolines to not use the CodeBlock. + + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + + Make call_JSFunction & call_arityCheck return the callee, don't expect to be passed the CodeBlock. + + * runtime/Executable.cpp: + (JSC::FunctionExecutable::generateBytecode): + (JSC::FunctionExecutable::recompile): + (JSC::FunctionExecutable::FunctionExecutable): + * runtime/Executable.h: + (JSC::ExecutableBase::): + (JSC::ExecutableBase::ExecutableBase): + (JSC::FunctionExecutable::isHostFunction): + + Add m_numParameters. + + * runtime/JSFunction.cpp: + (JSC::JSFunction::~JSFunction): + + Only call generatedBytecode() on JSFunctions non-host FunctionExecutables. + +2009-08-20 Yongjun Zhang <yongjun.zhang@nokia.com> + + Reviewed by Eric Seidel. + + https://bugs.webkit.org/show_bug.cgi?id=28054 + + Use a helper function to work around winscw compiler forward declaration bug + regarding templated classes. + + Add parenthesis around (PassRefPtr::*UnspecifiedBoolType) to make winscw compiler + work with the default UnSpecifiedBoolType() operator, which removes the winscw + specific bool cast hack. + + * wtf/PassRefPtr.h: + (WTF::derefIfNotNull): + (WTF::PassRefPtr::~PassRefPtr): + +2009-08-19 Yong Li <yong.li@torchmobile.com> + + Reviewed by Gavin Barraclough. + + Change namespace ARM to ARMRegisters + X86 to X86Registers to avoid conflict with macros + https://bugs.webkit.org/show_bug.cgi?id=28428 + + * assembler/ARMAssembler.cpp: + * assembler/ARMAssembler.h: + * assembler/ARMv7Assembler.h: + * assembler/MacroAssemblerARM.h: + * assembler/MacroAssemblerARMv7.h: + * assembler/MacroAssemblerX86Common.h: + * assembler/MacroAssemblerX86_64.h: + * assembler/X86Assembler.h: + * jit/JIT.h: + * jit/JITArithmetic.cpp: + * jit/JITInlineMethods.h: + * jit/JITOpcodes.cpp: + * wrec/WRECGenerator.cpp: + * wrec/WRECGenerator.h: + * yarr/RegexJIT.cpp: + +2009-08-19 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Devirtualise marking + https://bugs.webkit.org/show_bug.cgi?id=28294 + + We actually need to mark the value in a number object if we're using the + 32bit number representation. + + * runtime/NumberObject.h: + (JSC::NumberObject::createStructure): + +2009-08-19 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Darin Adler. + + We probably shouldn't be keeping the AST for eval nodes around forevar. + https://bugs.webkit.org/show_bug.cgi?id=28469 + + EvalNodes don't destroyData() (delete their parser data) since they need to hold onto + their varStack. Copy a list of variable onto EvalCodeBlock, and this can go away. + + * bytecode/CodeBlock.h: + (JSC::EvalCodeBlock::variable): + (JSC::EvalCodeBlock::numVariables): + (JSC::EvalCodeBlock::adoptVariables): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + * parser/Nodes.h: + * runtime/Executable.cpp: + (JSC::EvalExecutable::generateBytecode): + * runtime/Executable.h: + +2009-08-19 Jungshik Shin <jshin@chromium.org> + + Reviewed by Darin Adler. + + http://bugs.webkit.org/show_bug.cgi?id=28441 + + Fix a build issue with ICU 4.2 or later on Windows with Visual C++. + Instead of defining all isXXX and toupper/tolower as + WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h, + #define them to be different by prepending 'WTF_...ASCIIType_h' with + the originial names like 'toupper_WTF_...ASCIIType_h'. + + * wtf/DisallowCType.h: + +2009-08-18 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Assigning a function to an object should always use the existing transition, even if the transition is not specialized + https://bugs.webkit.org/show_bug.cgi?id=28442 + + Check for an unspecialized transition as an alternative to always failing if specialisation does not match. + + * runtime/Structure.cpp: + (JSC::Structure::addPropertyTransitionToExistingStructure): + +2009-08-18 Dirk Schulze <krit@webkit.org> + + Reviewed by Oliver Hunt. + + Added additional getter to ByteArray with an unsigned char as return. + ByteArray can take unsigned char directly now. + + * wtf/ByteArray.h: + (WTF::ByteArray::set): + (WTF::ByteArray::get): + +2009-08-18 Peter Kasting <pkasting@google.com> + + Reviewed by Eric Seidel. + + https://bugs.webkit.org/show_bug.cgi?id=28415 + Set svn:eol-style CRLF on all .sln and .vcproj files that don't already + have it. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.vcproj: + * JavaScriptCore.vcproj/testapi/testapi.vcproj: + +2009-08-18 Xan Lopez <xlopez@igalia.com> + + Try to fix the GTK+ build. + + * GNUmakefile.am: + +2009-08-17 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Sam Weinig. + + No, silly runtime, AST nodes are not for you. + + We still use AST nodes (ScopeNodes, particularly FunctionBodyNodes) within + the runtime, which means that these nodes must be persisted outside of the + arena, contain both parser & runtime data, etc. This is all a bit of a mess. + + Move functionality into a new FunctionExecutable class. + + * API/JSCallbackFunction.cpp: + * API/JSObjectRef.cpp: + * JavaScriptCore.exp: + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::CodeBlock): + (JSC::CodeBlock::markAggregate): + (JSC::CodeBlock::reparseForExceptionInfoIfNecessary): + (JSC::CodeBlock::lineNumberForBytecodeOffset): + (JSC::CodeBlock::shrinkToFit): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::getBytecodeIndex): + (JSC::CodeBlock::discardBytecode): + (JSC::CodeBlock::instructionCount): + (JSC::CodeBlock::getJITCode): + (JSC::CodeBlock::executablePool): + (JSC::CodeBlock::ownerExecutable): + (JSC::CodeBlock::extractExceptionInfo): + (JSC::CodeBlock::addFunctionDecl): + (JSC::CodeBlock::functionDecl): + (JSC::CodeBlock::numberOfFunctionDecls): + (JSC::CodeBlock::addFunctionExpr): + (JSC::CodeBlock::functionExpr): + (JSC::GlobalCodeBlock::GlobalCodeBlock): + (JSC::ProgramCodeBlock::ProgramCodeBlock): + (JSC::EvalCodeBlock::EvalCodeBlock): + (JSC::FunctionCodeBlock::FunctionCodeBlock): + (JSC::NativeCodeBlock::NativeCodeBlock): + * bytecode/EvalCodeCache.h: + * bytecode/SamplingTool.cpp: + (JSC::SamplingTool::doRun): + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::emitNewFunction): + (JSC::BytecodeGenerator::emitNewFunctionExpression): + * bytecompiler/BytecodeGenerator.h: + * debugger/Debugger.cpp: + (JSC::Debugger::recompileAllJSFunctions): + * interpreter/CachedCall.h: + (JSC::CachedCall::CachedCall): + * interpreter/CallFrameClosure.h: + * interpreter/Interpreter.cpp: + (JSC::Interpreter::unwindCallFrame): + (JSC::Interpreter::throwException): + (JSC::Interpreter::execute): + (JSC::Interpreter::prepareForRepeatCall): + (JSC::Interpreter::debug): + (JSC::Interpreter::privateExecute): + (JSC::Interpreter::retrieveLastCaller): + * interpreter/Interpreter.h: + * jit/JIT.cpp: + (JSC::JIT::privateCompile): + * jit/JIT.h: + (JSC::JIT::compile): + * jit/JITOpcodes.cpp: + (JSC::JIT::privateCompileCTIMachineTrampolines): + (JSC::JIT::emit_op_new_func): + (JSC::JIT::emit_op_new_func_exp): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + (JSC::): + * parser/Nodes.cpp: + (JSC::FunctionBodyNode::reparseDataIfNecessary): + * parser/Nodes.h: + (JSC::EvalNode::partialDestroyData): + * parser/Parser.h: + * profiler/ProfileGenerator.cpp: + * profiler/Profiler.cpp: + (JSC::Profiler::createCallIdentifier): + (JSC::createCallIdentifierFromFunctionImp): + * runtime/Arguments.h: + (JSC::Arguments::getArgumentsData): + (JSC::Arguments::Arguments): + (JSC::JSActivation::copyRegisters): + * runtime/ArrayPrototype.cpp: + (JSC::isNumericCompareFunction): + * runtime/CallData.h: + (JSC::): + * runtime/Collector.cpp: + (JSC::Heap::collect): + * runtime/ConstructData.h: + (JSC::): + * runtime/ExceptionHelpers.cpp: + (JSC::createUndefinedVariableError): + (JSC::createInvalidParamError): + (JSC::createNotAConstructorError): + (JSC::createNotAFunctionError): + (JSC::createNotAnObjectError): + * runtime/Executable.cpp: Added. + (JSC::EvalExecutable::generateBytecode): + (JSC::ProgramExecutable::generateBytecode): + (JSC::FunctionExecutable::generateBytecode): + (JSC::EvalExecutable::generateJITCode): + (JSC::ProgramExecutable::generateJITCode): + (JSC::FunctionExecutable::generateJITCode): + (JSC::FunctionExecutable::isHostFunction): + (JSC::FunctionExecutable::markAggregate): + (JSC::FunctionExecutable::reparseExceptionInfo): + (JSC::EvalExecutable::reparseExceptionInfo): + (JSC::FunctionExecutable::recompile): + (JSC::FunctionExecutable::FunctionExecutable): + * runtime/Executable.h: + (JSC::ExecutableBase::~ExecutableBase): + (JSC::ExecutableBase::ExecutableBase): + (JSC::ExecutableBase::source): + (JSC::ExecutableBase::sourceID): + (JSC::ExecutableBase::lastLine): + (JSC::ExecutableBase::usesEval): + (JSC::ExecutableBase::usesArguments): + (JSC::ExecutableBase::needsActivation): + (JSC::ExecutableBase::astNode): + (JSC::ExecutableBase::generatedJITCode): + (JSC::ExecutableBase::getExecutablePool): + (JSC::EvalExecutable::EvalExecutable): + (JSC::EvalExecutable::bytecode): + (JSC::EvalExecutable::varStack): + (JSC::EvalExecutable::evalNode): + (JSC::EvalExecutable::jitCode): + (JSC::ProgramExecutable::ProgramExecutable): + (JSC::ProgramExecutable::reparseExceptionInfo): + (JSC::ProgramExecutable::bytecode): + (JSC::ProgramExecutable::programNode): + (JSC::ProgramExecutable::jitCode): + (JSC::FunctionExecutable::FunctionExecutable): + (JSC::FunctionExecutable::name): + (JSC::FunctionExecutable::bytecode): + (JSC::FunctionExecutable::generatedBytecode): + (JSC::FunctionExecutable::usesEval): + (JSC::FunctionExecutable::usesArguments): + (JSC::FunctionExecutable::parameterCount): + (JSC::FunctionExecutable::paramString): + (JSC::FunctionExecutable::isGenerated): + (JSC::FunctionExecutable::body): + (JSC::FunctionExecutable::jitCode): + (JSC::FunctionExecutable::createNativeThunk): + * runtime/FunctionConstructor.cpp: + (JSC::constructFunction): + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncToString): + * runtime/JSActivation.cpp: + (JSC::JSActivation::JSActivation): + (JSC::JSActivation::markChildren): + (JSC::JSActivation::isDynamicScope): + (JSC::JSActivation::argumentsGetter): + * runtime/JSActivation.h: + (JSC::JSActivation::JSActivationData::JSActivationData): + * runtime/JSFunction.cpp: + (JSC::JSFunction::isHostFunction): + (JSC::JSFunction::JSFunction): + (JSC::JSFunction::~JSFunction): + (JSC::JSFunction::markChildren): + (JSC::JSFunction::getCallData): + (JSC::JSFunction::call): + (JSC::JSFunction::lengthGetter): + (JSC::JSFunction::getConstructData): + (JSC::JSFunction::construct): + * runtime/JSFunction.h: + (JSC::JSFunction::executable): + (JSC::FunctionExecutable::make): + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + (JSC::JSGlobalData::numericCompareFunction): + * runtime/JSGlobalData.h: + +2009-08-17 Mark Rowe <mrowe@apple.com> + + Reviewed by Darin Adler. + + Fix 300,000+ leaks seen during the regression tests. + + EvalCodeCache::get was heap-allocating an EvalExecutable instance without adopting the initial reference. + While fixing this we noticed that EvalExecutable was a RefCounted type that was sometimes stack allocated. + To make this cleaner and to prevent clients from attempting to ref a stack-allocated instance, we move the + refcounting down to a new CacheableEvalExecutable class that derives from EvalExecutable. EvalCodeCache::get + now uses CacheableEvalExecutable::create and avoids the leak. + + * bytecode/EvalCodeCache.h: + (JSC::EvalCodeCache::get): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::callEval): + * runtime/Executable.h: + (JSC::CacheableEvalExecutable::create): + (JSC::CacheableEvalExecutable::CacheableEvalExecutable): + +2009-08-17 Oliver Hunt <oliver@apple.com> + + RS=Mark Rowe. + + REGRESSION (r47292): Prototype.js is broken by ES5 Arguments changes + https://bugs.webkit.org/show_bug.cgi?id=28341 + <rdar://problem/7145615> + + Reverting r47292. Alas Prototype.js breaks with Arguments inheriting + from Array as ES5 attempted. Prototype.js defines $A in terms of a + function it places on (among other global objects) the Array prototype, + thus breaking $A for arrays. + + * runtime/Arguments.h: + (JSC::Arguments::Arguments): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::markChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::JSGlobalObjectData::JSGlobalObjectData): + * runtime/ObjectPrototype.cpp: + (JSC::ObjectPrototype::ObjectPrototype): + * runtime/ObjectPrototype.h: + * tests/mozilla/ecma_3/Function/arguments-001.js: + +2009-08-17 Peter Kasting <pkasting@google.com> + + Reviewed by Steve Falkenburg. + + https://bugs.webkit.org/show_bug.cgi?id=27323 + Only add Cygwin to the path when it isn't already there. This avoids + causing problems for people who purposefully have non-Cygwin versions of + executables like svn in front of the Cygwin ones in their paths. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.vcproj: + * JavaScriptCore.vcproj/WTF/WTFCommon.vsprops: + * JavaScriptCore.vcproj/jsc/jscCommon.vsprops: + * JavaScriptCore.vcproj/testapi/testapiCommon.vsprops: + +2009-08-17 Xan Lopez <xlopez@igalia.com> + + Reviewed by Mark Rowe. + + Fix build with FAST_MALLOC_MATCH_VALIDATION enabled. + + * wtf/FastMalloc.cpp: + (WTF::fastMalloc): + (WTF::fastCalloc): + (WTF::fastRealloc): + +2009-08-16 Holger Hans Peter Freyther <zecke@selfish.org> + + Reviewed by Mark Rowe. + + Fix crash on ./ecma_2/RegExp/exec-002.js. + https://bugs.webkit.org/show_bug.cgi?id=28353 + + Change the order of freeParenthesesDisjunctionContext and + popParenthesesDisjunctionContext on all call sites as the pop + method is accessing backTrack->lastContext which is the context + that is about to be freed. + + * yarr/RegexInterpreter.cpp: + (JSC::Yarr::Interpreter::parenthesesDoBacktrack): + (JSC::Yarr::Interpreter::backtrackParentheses): + +2009-08-16 Holger Hans Peter Freyther <zecke@selfish.org> + + Reviewed by Mark Rowe. + + https://bugs.webkit.org/show_bug.cgi?id=28352 + + Fix coding style violations. Use m_ for C++ class members. Remove + trailing whitespace on empty lines. + + * yarr/RegexInterpreter.cpp: + (JSC::Yarr::Interpreter::ParenthesesDisjunctionContext::ParenthesesDisjunctionContext): + (JSC::Yarr::Interpreter::tryConsumeCharacter): + (JSC::Yarr::Interpreter::tryConsumeBackReference): + (JSC::Yarr::Interpreter::parenthesesDoBacktrack): + (JSC::Yarr::Interpreter::backtrackParentheses): + (JSC::Yarr::ByteCompiler::ByteCompiler): + (JSC::Yarr::ByteCompiler::compile): + (JSC::Yarr::ByteCompiler::checkInput): + (JSC::Yarr::ByteCompiler::assertionBOL): + (JSC::Yarr::ByteCompiler::assertionEOL): + (JSC::Yarr::ByteCompiler::assertionWordBoundary): + (JSC::Yarr::ByteCompiler::atomPatternCharacter): + (JSC::Yarr::ByteCompiler::atomCharacterClass): + (JSC::Yarr::ByteCompiler::atomBackReference): + (JSC::Yarr::ByteCompiler::atomParenthesesSubpatternBegin): + (JSC::Yarr::ByteCompiler::atomParentheticalAssertionBegin): + (JSC::Yarr::ByteCompiler::popParenthesesStack): + (JSC::Yarr::ByteCompiler::closeAlternative): + (JSC::Yarr::ByteCompiler::closeBodyAlternative): + (JSC::Yarr::ByteCompiler::atomParenthesesEnd): + (JSC::Yarr::ByteCompiler::regexBegin): + (JSC::Yarr::ByteCompiler::alterantiveBodyDisjunction): + (JSC::Yarr::ByteCompiler::alterantiveDisjunction): + (JSC::Yarr::ByteCompiler::emitDisjunction): + +2009-08-15 Mark Rowe <mrowe@apple.com> + + Fix the build with JIT disabled. + + * runtime/Arguments.h: Only compile the jitCode method when the JIT is enabled. + * runtime/Executable.h: Include PrototypeFunction.h so the compiler knows what + NativeFunctionWrapper is when the JIT is disabled. + +2009-08-15 Adam Bergkvist <adam.bergkvist@ericsson.com> + + Reviewed by Sam Weinig. + + Added ENABLE_EVENTSOURCE flag. + https://bugs.webkit.org/show_bug.cgi?id=14997 + + * Configurations/FeatureDefines.xcconfig: + +2009-08-14 Gavin Barraclough <barraclough@apple.com> + + * parser/Parser.h: + (JSC::EvalExecutable::parse): + (JSC::ProgramExecutable::parse): + * runtime/Executable.h: + +2009-08-14 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Remove AST nodes from use within the Runtime (outside of parsing), stage 1 + https://bugs.webkit.org/show_bug.cgi?id=28330 + + Remove the EvalNode and ProgramNode from use in the runtime. They still exist + after this patch, but are hidden behind EvalExecutable and FunctionExecutable, + and are also still reachable behind CodeBlock::m_ownerNode. + + The next step will be to beat back FunctionBodyNode in the same fashion. + Then remove the usage via CodeBlock, then only construct these nodes only on + demand during bytecode generation. + + * JavaScriptCore.xcodeproj/project.pbxproj: + * bytecode/CodeBlock.h: + (JSC::GlobalCodeBlock::GlobalCodeBlock): + (JSC::GlobalCodeBlock::~GlobalCodeBlock): + (JSC::ProgramCodeBlock::ProgramCodeBlock): + (JSC::EvalCodeBlock::EvalCodeBlock): + (JSC::FunctionCodeBlock::FunctionCodeBlock): + (JSC::NativeCodeBlock::NativeCodeBlock): + * bytecode/EvalCodeCache.h: + (JSC::EvalCodeCache::get): + * debugger/Debugger.cpp: + (JSC::evaluateInGlobalCallFrame): + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::evaluate): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::callEval): + (JSC::Interpreter::execute): + * interpreter/Interpreter.h: + * parser/Nodes.cpp: + (JSC::FunctionBodyNode::createNativeThunk): + (JSC::FunctionBodyNode::generateBytecode): + (JSC::FunctionBodyNode::bytecodeForExceptionInfoReparse): + * parser/Parser.h: + (JSC::Parser::parse): + (JSC::Parser::reparse): + (JSC::Parser::parseFunctionFromGlobalCode): + (JSC::::parse): + * runtime/Completion.cpp: + (JSC::checkSyntax): + (JSC::evaluate): + * runtime/Error.cpp: + (JSC::throwError): + * runtime/Error.h: + * runtime/Executable.h: Added. + (JSC::TemplateExecutable::TemplateExecutable): + (JSC::TemplateExecutable::markAggregate): + (JSC::TemplateExecutable::sourceURL): + (JSC::TemplateExecutable::lineNo): + (JSC::TemplateExecutable::bytecode): + (JSC::TemplateExecutable::jitCode): + (JSC::EvalExecutable::EvalExecutable): + (JSC::ProgramExecutable::ProgramExecutable): + * runtime/FunctionConstructor.cpp: + (JSC::constructFunction): + * runtime/FunctionConstructor.h: + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::numericCompareFunction): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::~JSGlobalObject): + (JSC::JSGlobalObject::markChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::codeBlocks): + * runtime/JSGlobalObjectFunctions.cpp: + (JSC::globalFuncEval): + +2009-08-14 Darin Adler <darin@apple.com> + + Reviewed by Sam Weinig. + + Rename the confusing isObject(<class>) to inherits(<class>). + It still works on non-objects, returning false. + + * runtime/ArrayConstructor.cpp: + (JSC::arrayConstructorIsArray): Removed unneeded isObject call + and updated remaining isObject call to new name, inherits. + + * runtime/JSCell.h: Renamed isObject(<class>) to inherits(<class>) + but more importantly, made it non-virtual (it was already inline) + so it is now as fast as JSObject::inherits was. + + * runtime/JSObject.h: Removed inherits function since the one + in the base class is fine as-is. Also made various JSCell functions + that should not be called on JSObject uncallable by making them + both private and not implemented. + (JSC::JSCell::inherits): Updated name. + (JSC::JSValue::inherits): Ditto. + + * debugger/Debugger.cpp: + (JSC::Debugger::recompileAllJSFunctions): + * interpreter/Interpreter.cpp: + (JSC::Interpreter::unwindCallFrame): + * runtime/ArrayPrototype.cpp: + (JSC::arrayProtoFuncToString): + (JSC::arrayProtoFuncToLocaleString): + (JSC::arrayProtoFuncConcat): + * runtime/BooleanPrototype.cpp: + (JSC::booleanProtoFuncToString): + (JSC::booleanProtoFuncValueOf): + * runtime/DateConstructor.cpp: + (JSC::constructDate): + * runtime/DatePrototype.cpp: + (JSC::dateProtoFuncToString): + (JSC::dateProtoFuncToUTCString): + (JSC::dateProtoFuncToISOString): + (JSC::dateProtoFuncToDateString): + (JSC::dateProtoFuncToTimeString): + (JSC::dateProtoFuncToLocaleString): + (JSC::dateProtoFuncToLocaleDateString): + (JSC::dateProtoFuncToLocaleTimeString): + (JSC::dateProtoFuncGetTime): + (JSC::dateProtoFuncGetFullYear): + (JSC::dateProtoFuncGetUTCFullYear): + (JSC::dateProtoFuncToGMTString): + (JSC::dateProtoFuncGetMonth): + (JSC::dateProtoFuncGetUTCMonth): + (JSC::dateProtoFuncGetDate): + (JSC::dateProtoFuncGetUTCDate): + (JSC::dateProtoFuncGetDay): + (JSC::dateProtoFuncGetUTCDay): + (JSC::dateProtoFuncGetHours): + (JSC::dateProtoFuncGetUTCHours): + (JSC::dateProtoFuncGetMinutes): + (JSC::dateProtoFuncGetUTCMinutes): + (JSC::dateProtoFuncGetSeconds): + (JSC::dateProtoFuncGetUTCSeconds): + (JSC::dateProtoFuncGetMilliSeconds): + (JSC::dateProtoFuncGetUTCMilliseconds): + (JSC::dateProtoFuncGetTimezoneOffset): + (JSC::dateProtoFuncSetTime): + (JSC::setNewValueFromTimeArgs): + (JSC::setNewValueFromDateArgs): + (JSC::dateProtoFuncSetYear): + (JSC::dateProtoFuncGetYear): + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncToString): + * runtime/JSActivation.cpp: + (JSC::JSActivation::argumentsGetter): + * runtime/JSValue.h: + * runtime/RegExpConstructor.cpp: + (JSC::constructRegExp): + * runtime/RegExpPrototype.cpp: + (JSC::regExpProtoFuncTest): + (JSC::regExpProtoFuncExec): + (JSC::regExpProtoFuncCompile): + (JSC::regExpProtoFuncToString): + * runtime/ScopeChain.cpp: + (JSC::ScopeChain::localDepth): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncReplace): + (JSC::stringProtoFuncToString): + (JSC::stringProtoFuncMatch): + (JSC::stringProtoFuncSearch): + (JSC::stringProtoFuncSplit): + Updated to new name, inherits, from old name, isObject. + +2009-07-31 Harald Fernengel <harald.fernengel@nokia.com> + + Reviewed by Simon Hausmann. + + Adding QNX as a platform. Currently only tested with Qt. + + https://bugs.webkit.org/show_bug.cgi?id=27885 + + * JavaScriptCore/runtime/Collector.cpp: Added retrieving of stack base + since QNX doesn't have the pthread _nt functions + * JavaScriptCore/wtf/Platform.h: Added WTF_PLATFORM_QNX and corresponding + defines + * WebCore/bridge/npapi.h: Build fix for missing typedefs on QNX + +2009-08-14 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Simon Hausmann. + + Currently generic ARM and ARMv7 platforms work only with JSVALUE32 + https://bugs.webkit.org/show_bug.cgi?id=28300 + + * wtf/Platform.h: + +2009-08-14 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Simon Hausmann. + + Enable JIT on ARM for QT by default + https://bugs.webkit.org/show_bug.cgi?id=28259 + + * wtf/Platform.h: + +2009-08-14 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Simon Hausmann. + + Enable YARR_JIT on ARM for QT by default + https://bugs.webkit.org/show_bug.cgi?id=28259 + + * wtf/Platform.h: + +2009-08-14 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + [ES5] Arguments object should inherit from Array + https://bugs.webkit.org/show_bug.cgi?id=28298 + + Make the Arguments object conform to the behaviour specified in ES5. + The simple portion of this is to make Arguments use Array.prototype + as its prototype rather than Object.prototype. + + The spec then requires us to set instance.constructor to the pristine + Object constructor, and instance.toString and instance.toLocaleString + to the pristine versions from Object.prototype. To do this we now + make the ObjectPrototype constructor return its toString and + toLocaleString functions (similar to the call and apply functions + from FunctionPrototype). + + Oddly enough this reports itself as a slight win, but given the code + isn't hit in the tests that claim to have improved I put this down to + code motion. + + * runtime/Arguments.h: + (JSC::Arguments::Arguments): + (JSC::Arguments::initializeStandardProperties): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + (JSC::JSGlobalObject::markChildren): + * runtime/JSGlobalObject.h: + (JSC::JSGlobalObject::JSGlobalObjectData::JSGlobalObjectData): + (JSC::JSGlobalObject::objectConstructor): + (JSC::JSGlobalObject::objectToStringFunction): + (JSC::JSGlobalObject::objectToLocaleStringFunction): + * runtime/ObjectPrototype.cpp: + (JSC::ObjectPrototype::ObjectPrototype): + * runtime/ObjectPrototype.h: + * tests/mozilla/ecma_3/Function/arguments-001.js: + Update test to new es5 behaviour + +2009-08-14 Oliver Hunt <oliver@apple.com> + + Remove MarkStack::drain from the JSC exports file + + MarkStack::drain is now marked inline, the including it in the exports file + produces an ld warning + + * JavaScriptCore.exp: + +2009-08-13 Sam Weinig <sam@webkit.org> + + Reviewed by Oliver Hunt. + + Remove accidentally left in debugging statement. + + * runtime/JSArray.h: + (JSC::MarkStack::drain): + +2009-08-13 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + [ES5] Implement Array.isArray + https://bugs.webkit.org/show_bug.cgi?id=28296 + + Add support for Array.isArray to the Array constructor + + * runtime/ArrayConstructor.cpp: + (JSC::ArrayConstructor::ArrayConstructor): + (JSC::arrayConstructorIsArray): + * runtime/ArrayConstructor.h: + * runtime/CommonIdentifiers.h: + * runtime/JSArray.h: + (JSC::MarkStack::drain): + * runtime/JSGlobalObject.cpp: + (JSC::JSGlobalObject::reset): + +2009-08-13 Oliver Hunt <oliver@apple.com> + + Reviewed by NOBODY (Buildfix). + + Attempt to fix windows build + + * runtime/Collector.cpp: + +2009-08-13 Oliver Hunt <oliver@apple.com> + + Reviewed by Maciej Stachowiak. + + Devirtualise marking + https://bugs.webkit.org/show_bug.cgi?id=28294 + + Add a bit to TypeInfo to indicate that an object uses the standard + JSObject::markChildren method. This allows us to devirtualise marking + of most objects (though a branch is still needed). We also add a branch + to identify arrays thus devirtualising marking in that case as well. + + In order to make the best use of this devirtualisation I've also reworked + the MarkStack::drain() logic to make the iteration more efficient. + + * API/JSCallbackConstructor.h: + (JSC::JSCallbackConstructor::createStructure): + * API/JSCallbackFunction.h: + (JSC::JSCallbackFunction::createStructure): + * JavaScriptCore.exp: + * runtime/BooleanObject.h: + (JSC::BooleanObject::createStructure): + * runtime/FunctionPrototype.h: + (JSC::FunctionPrototype::createStructure): + * runtime/InternalFunction.h: + (JSC::InternalFunction::createStructure): + * runtime/JSAPIValueWrapper.h: + (JSC::JSAPIValueWrapper::JSAPIValueWrapper): + * runtime/JSArray.cpp: + (JSC::JSArray::markChildren): + * runtime/JSArray.h: + (JSC::JSArray::markChildrenDirect): + (JSC::MarkStack::drain): + * runtime/JSByteArray.cpp: + (JSC::JSByteArray::createStructure): + * runtime/JSCell.h: + (JSC::MarkStack::append): + * runtime/JSGlobalData.cpp: + (JSC::JSGlobalData::JSGlobalData): + * runtime/JSNumberCell.h: + (JSC::JSNumberCell::createStructure): + * runtime/JSONObject.h: + (JSC::JSONObject::createStructure): + * runtime/JSObject.cpp: + (JSC::JSObject::markChildren): + * runtime/JSObject.h: + (JSC::JSObject::markChildrenDirect): + (JSC::JSObject::createStructure): + * runtime/JSString.h: + (JSC::JSString::createStructure): + * runtime/JSType.h: + (JSC::): + * runtime/MarkStack.h: + (JSC::MarkStack::MarkStack): + (JSC::MarkStack::MarkSet::MarkSet): + (JSC::MarkStack::MarkStackArray::last): + * runtime/MathObject.h: + (JSC::MathObject::createStructure): + * runtime/NumberConstructor.h: + (JSC::NumberConstructor::createStructure): + * runtime/NumberObject.h: + (JSC::NumberObject::createStructure): + * runtime/RegExpConstructor.h: + (JSC::RegExpConstructor::createStructure): + * runtime/RegExpObject.h: + (JSC::RegExpObject::createStructure): + * runtime/StringObjectThatMasqueradesAsUndefined.h: + (JSC::StringObjectThatMasqueradesAsUndefined::createStructure): + * runtime/TypeInfo.h: + (JSC::TypeInfo::hasDefaultMark): + +2009-08-13 Darin Adler <darin@apple.com> + + Reviewed by Mark Rowe. + + Some small bits of housekeeping. + + * JavaScriptCore.xcodeproj/project.pbxproj: Make Parser.h + project instead of private. Remove JSONObject.lut.h. + + * assembler/ARMAssembler.h: Remove unneeded WTF prefix. + * assembler/AssemblerBufferWithConstantPool.h: Ditto. + * bytecompiler/BytecodeGenerator.h: Ditto. + + * wtf/SegmentedVector.h: Add a "using" statement as we do + with the other WTF headers. + +2009-08-13 Darin Adler <darin@apple.com> + + Fix Tiger build. + + * parser/Grammar.y: Use a template function so we can compile + setStatementLocation even if it comes before YYLTYPE is defined. + +2009-08-13 Darin Adler <darin@apple.com> + + Reviewed by George Staikos. + + Too much use of void* in Grammar.y + https://bugs.webkit.org/show_bug.cgi?id=28287 + + * parser/Grammar.y: Changed all the helper functions to + take a JSGlobalData* instead of a void*. A couple formatting + tweaks that I missed when breaking this into pieces. + +2009-08-13 Darin Adler <darin@apple.com> + + Reviewed by George Staikos. + + Another part of https://bugs.webkit.org/show_bug.cgi?id=28287 + + * parser/Grammar.y: Reduced and sorted includes. Tweaked comment + format. Marked a few more functions inline. + +2009-08-13 Darin Adler <darin@apple.com> + + Reviewed by George Staikos. + + Another part of https://bugs.webkit.org/show_bug.cgi?id=28287 + + * parser/Grammar.y: Pass the number to the PropertyNode instead of + first turning it into an Identifier. + + * parser/NodeConstructors.h: + (JSC::PropertyNode::PropertyNode): Add an overload that takes a double + so the code to convert to a string can be here instead of Grammar.y. + * parser/Nodes.h: Ditto. + +2009-08-13 Darin Adler <darin@apple.com> + + Reviewed by George Staikos. + + Another part of https://bugs.webkit.org/show_bug.cgi?id=28287 + + * parser/Grammar.y: Eliminate the DBG macro. + +2009-08-13 Darin Adler <darin@apple.com> + + Reviewed by George Staikos. + + Another part of https://bugs.webkit.org/show_bug.cgi?id=28287 + + * parser/Grammar.y: Eliminate the SET_EXCEPTION_LOCATION macro. + +2009-08-13 Darin Adler <darin@apple.com> + + Reviewed by George Staikos. + + George asked me to break the patch from + https://bugs.webkit.org/show_bug.cgi?id=28287 + into smaller pieces and land it in stages. + + * parser/Grammar.y: Eliminate the LEXER macro. + +2009-08-13 Mark Rowe <mrowe@apple.com> + + Try some more to fix the Windows build. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Export a new symbol. + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: Ditto. + +2009-08-13 Mark Rowe <mrowe@apple.com> + + Try and fix the Windows build. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: Export a new symbol. + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: Ditto. + +2009-08-13 Darin Adler <darin@apple.com> + + Reviewed by David Levin. + + JavaScriptCore tweaks to get ready for the parser arena + https://bugs.webkit.org/show_bug.cgi?id=28243 + + Eliminate dependencies on Nodes.h outside JavaScriptCore, + and cut down on them inside JavaScriptCore. + + Change regular expression parsing to use identifiers as + with other strings we parse. + + Fix a couple things that are needed to use const Identifier + more, which will be part of the parser arena work. + + * JavaScriptCore.exp: Resorted and updated. + + * JavaScriptCore.xcodeproj/project.pbxproj: Changed + CollectorHeapIterator.h to be project-internal. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::emitPushNewScope): Added const. + * bytecompiler/BytecodeGenerator.h: Ditto. + + * debugger/Debugger.cpp: + (JSC::Debugger::recompileAllJSFunctions): Moved this function + here from WebCore. Here is better since it uses so many internals. + Removed unimportant optimization for the no listener case. + * debugger/Debugger.h: Ditto. Also removed unneeded include + and tweaked formatting and comments. + + * debugger/DebuggerCallFrame.cpp: + (JSC::DebuggerCallFrame::functionName): Call asFunction instead + of doing the unchecked static_cast. + (JSC::DebuggerCallFrame::calculatedFunctionName): Ditto. + + * jit/JITStubs.cpp: + (JSC::op_call_JSFunction): Call isHostFunction on the body rather + than on the JSFunction. + (JSC::vm_lazyLinkCall): Ditto. + (JSC::op_construct_JSConstruct): Ditto. + + * parser/Grammar.y: Changed callers to use new scanRegExp with + out arguments instead of relying on state in the Lexer. And + callers that just want to skip a regular expression to use + skipRegExp. + + * parser/Lexer.cpp: + (JSC::Lexer::scanRegExp): Changed to use out arguments, and to + add a prefix argument so we can add in the "=" character as needed. + Also rewrote to streamline the logic a bit inspired by suggestions + by David Levin. + (JSC::Lexer::skipRegExp): Added. Version of the function above that + does not actually put the regular expression into a string. + (JSC::Lexer::clear): Removed code to clear m_pattern and m_flags. + * parser/Lexer.h: Changed scanRegExp to have out arguments. Added + skipRegExp. Eliminated pattern, flags, m_pattern, and m_flags. + + * parser/NodeConstructors.h: + (JSC::RegExpNode::RegExpNode): Changed to take const Identifier&. + * parser/Nodes.cpp: + (JSC::RegExpNode::emitBytecode): Changed since m_pattern and + m_flags are now Identifier instead of UString. + (JSC::FunctionBodyNode::make): Moved this function here instead + of putting it in the JSFunction.h header. + * parser/Nodes.h: Changed RegExpNode to use Identifier. + + * profiler/Profiler.cpp: + (JSC::Profiler::createCallIdentifier): Changed to use isHostFunction + on the body instead of on the JSFunction object. + * runtime/FunctionPrototype.cpp: + (JSC::functionProtoFuncToString): Ditto. + + * runtime/JSFunction.cpp: + (JSC::JSFunction::isHostFunction): Moved here from header. + (JSC::JSFunction::isHostFunctionNonInline): Added. + (JSC::JSFunction::JSFunction): Removed unneeded initialization of + m_body to 0. + (JSC::JSFunction::setBody): Moved here from header. + + * runtime/JSFunction.h: Removed unneeded includes. Moved private + constructor down to the private section. Made virtual functions + private. Removed unneeded overload of setBody and moved the body + of the function into the .cpp file. Changed assertions to use + the non-inline version of isHostFunction. + + * runtime/PropertySlot.cpp: + (JSC::PropertySlot::functionGetter): Use asFunction instead + of doing the unchecked static_cast. + + * wtf/SegmentedVector.h: + (WTF::SegmentedVector::isEmpty): Added. + +2009-08-13 Mark Rowe <mrowe@apple.com> + + Rubber-stamped by Darin Adler. + + Use the version of operator new that takes a JSGlobalData when allocating FuncDeclNode and FuncExprNode + from within the grammar to prevent these nodes from being leaked. + + * parser/Grammar.y: + +2009-08-13 Simon Hausmann <simon.hausmann@nokia.com> + + Reviewed by Ariya Hidayat. + + Remove the special-case for Qt wrt JSVALUE_32 introduced in + r46709. It must've been a dependency issue on the bot, as + after a manual build all the tests pass on amd64 and ia32. + + * wtf/Platform.h: + +2009-08-12 Gabor Loki <loki@inf.u-szeged.hu> + + Reviewed by Gavin Barraclough. + + Add optimize call and property access support for ARM JIT. + https://bugs.webkit.org/show_bug.cgi?id=24986 + + For tightly coupled sequences the BEGIN_UNINTERRUPTED_SEQUENCE and + END_UNINTERRUPTED_SEQUENCE macros have been introduced which ensure + space for instructions and constants of the named sequence. This + method is vital for those architecture which are using constant pool. + + The 'latePatch' method - which was linked to JmpSrc - is replaced with + a port specific solution (each calls are marked to place their address + on the constant pool). + + * assembler/ARMAssembler.cpp: + (JSC::ARMAssembler::linkBranch): + (JSC::ARMAssembler::executableCopy): Add extra align for constant pool. + * assembler/ARMAssembler.h: + (JSC::ARMAssembler::JmpSrc::JmpSrc): + (JSC::ARMAssembler::sizeOfConstantPool): + (JSC::ARMAssembler::jmp): + (JSC::ARMAssembler::linkCall): + * assembler/ARMv7Assembler.h: + * assembler/AbstractMacroAssembler.h: + * assembler/AssemblerBufferWithConstantPool.h: + (JSC::AssemblerBufferWithConstantPool::flushIfNoSpaceFor): Fix the + computation of the remaining space. + * assembler/MacroAssemblerARM.h: + (JSC::MacroAssemblerARM::branch32): + (JSC::MacroAssemblerARM::nearCall): + (JSC::MacroAssemblerARM::call): + (JSC::MacroAssemblerARM::branchPtrWithPatch): + (JSC::MacroAssemblerARM::ensureSpace): + (JSC::MacroAssemblerARM::sizeOfConstantPool): + (JSC::MacroAssemblerARM::prepareCall): + * assembler/X86Assembler.h: + * jit/JIT.h: + * jit/JITCall.cpp: + (JSC::JIT::compileOpCall): + * jit/JITInlineMethods.h: + (JSC::JIT::beginUninterruptedSequence): + (JSC::JIT::endUninterruptedSequence): + * jit/JITPropertyAccess.cpp: + (JSC::JIT::emit_op_method_check): + (JSC::JIT::compileGetByIdHotPath): + (JSC::JIT::compileGetByIdSlowCase): + (JSC::JIT::emit_op_put_by_id): + +2009-08-12 Gavin Barraclough <barraclough@apple.com> + + Rubber Stamped by Dave Kilzer. + + Disable WTF_USE_JSVALUE32_64 on iPhone for now (support not yet added for ARMv7). + + * wtf/Platform.h: + +2009-08-12 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Maciej Stachoviak. + + Ooops - moved code that had been accidentally added to op_new_func instead of + op_new_func_exp, to where it shoulds be. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::privateExecute): + * wtf/Platform.h: + +2009-08-12 Ada Chan <adachan@apple.com> + + Added workaround for the limitation that VirtualFree with MEM_RELEASE + can only accept the base address returned by VirtualAlloc when the region + was reserved and it can only free the entire region, and not a part of it. + + Reviewed by Oliver Hunt. + + * runtime/MarkStack.h: + (JSC::MarkStack::MarkStackArray::shrinkAllocation): + * runtime/MarkStackWin.cpp: + (JSC::MarkStack::releaseStack): + +2009-08-12 Balazs Kelemen <kelemen.balazs.3@stud.u-szeged.hu> + + Reviewed by Ariya Hidayat. + + Build fix: use std::numeric_limits<long long>::min() instead of LLONG_MIN + since LLONG_MIN is not defined in standard c++. + + * runtime/UString.cpp: + (JSC::UString::from): + +2009-08-12 Benjamin Otte <otte@gnome.org> + + Reviewed by Jan Alonzo. + + Buildfix for Gtk platforms debug builds. + + * GNUmakefile.am: Choose MarkStackPosix.cpp or MarkStackWin.cpp + depending on platform. + +2009-08-12 Simon Hausmann <simon.hausmann@nokia.com> + + Prospective build fix for Mac and 32-bit Windows. + + * runtime/UString.cpp: Include wtf/StringExtras.h for snprintf. + (JSC::UString::from): Use %lld instead of %I64d for snprintf + on non-windows platforms. + +2009-08-12 Prasanth Ullattil <prasanth.ullattil@nokia.com> + + Reviewed by Simon Hausmann. + + Fix compile error on 64Bit Windows, when UString::from + is called with an intptr_t. + + Added new UString::From overload with long long parameter. + + Thanks to Holger for the long long idea. + + * runtime/UString.cpp: + (JSC::UString::from): + * runtime/UString.h: + +2009-08-11 Oliver Hunt <oliver@apple.com> + + Reviewed by Mark Rowe. + + Minor style fixes. + + * runtime/UString.h: + (JSC::UString::Rep::createEmptyBuffer): + * wtf/FastMalloc.h: + (WTF::TryMallocReturnValue::getValue): + +2009-08-11 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Make it harder to misuse try* allocation routines + https://bugs.webkit.org/show_bug.cgi?id=27469 + + Jump through a few hoops to make it much harder to accidentally + miss null-checking of values returned by the try-* allocation + routines. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + * JavaScriptCore.xcodeproj/project.pbxproj: + * runtime/JSArray.cpp: + (JSC::JSArray::putSlowCase): + (JSC::JSArray::increaseVectorLength): + * runtime/StringPrototype.cpp: + (JSC::stringProtoFuncFontsize): + (JSC::stringProtoFuncLink): + * runtime/UString.cpp: + (JSC::allocChars): + (JSC::reallocChars): + (JSC::expandCapacity): + (JSC::UString::Rep::reserveCapacity): + (JSC::UString::expandPreCapacity): + (JSC::createRep): + (JSC::concatenate): + (JSC::UString::spliceSubstringsWithSeparators): + (JSC::UString::replaceRange): + (JSC::UString::append): + (JSC::UString::operator=): + * runtime/UString.h: + (JSC::UString::Rep::createEmptyBuffer): + * wtf/FastMalloc.cpp: + (WTF::tryFastZeroedMalloc): + (WTF::tryFastMalloc): + (WTF::tryFastCalloc): + (WTF::tryFastRealloc): + (WTF::TCMallocStats::tryFastMalloc): + (WTF::TCMallocStats::tryFastCalloc): + (WTF::TCMallocStats::tryFastRealloc): + * wtf/FastMalloc.h: + (WTF::TryMallocReturnValue::TryMallocReturnValue): + (WTF::TryMallocReturnValue::~TryMallocReturnValue): + (WTF::TryMallocReturnValue::operator PossiblyNull<T>): + (WTF::TryMallocReturnValue::getValue): + * wtf/Platform.h: + * wtf/PossiblyNull.h: Added. + (WTF::PossiblyNull::PossiblyNull): + (WTF::PossiblyNull::~PossiblyNull): + (WTF::::getValue): + +2009-08-11 Gavin Barraclough <barraclough@apple.com> + + Reviewed by NOBODY (build fix part deux). + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-08-11 Gavin Barraclough <barraclough@apple.com> + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-08-11 Gavin Barraclough <barraclough@apple.com> + + Reviewed by Oliver Hunt. + + Restrict use of FuncDeclNode & FuncExprNode to the parser. + https://bugs.webkit.org/show_bug.cgi?id=28209 + + These objects were also being referenced from the CodeBlock. By changing this + to just retain pointers to FunctionBodyNodes these classes can be restricted to + use during parsing. + + No performance impact (or sub-percent progression). + + * JavaScriptCore.exp: + Update symbols. + + * bytecode/CodeBlock.cpp: + (JSC::CodeBlock::mark): + (JSC::CodeBlock::reparseForExceptionInfoIfNecessary): + (JSC::CodeBlock::shrinkToFit): + * bytecode/CodeBlock.h: + (JSC::CodeBlock::addFunction): + (JSC::CodeBlock::function): + Unify m_functions & m_functionExpressions into a single Vector<RefPtr<FuncExprNode> >. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::BytecodeGenerator): + (JSC::BytecodeGenerator::addConstant): + (JSC::BytecodeGenerator::emitNewFunction): + (JSC::BytecodeGenerator::emitNewFunctionExpression): + * bytecompiler/BytecodeGenerator.h: + FunctionStacks now contain FunctionBodyNodes not FuncDeclNodes. + + * interpreter/Interpreter.cpp: + (JSC::Interpreter::execute): + (JSC::Interpreter::privateExecute): + Update to reflect chnages in CodeBlock. + + * jit/JITOpcodes.cpp: + (JSC::JIT::emit_op_new_func_exp): + * jit/JITStubs.cpp: + (JSC::DEFINE_STUB_FUNCTION): + * jit/JITStubs.h: + (JSC::): + Update to reflect chnages in CodeBlock. + + * parser/Grammar.y: + FunctionStacks now contain FunctionBodyNodes not FuncDeclNodes. + + * parser/NodeConstructors.h: + (JSC::FuncExprNode::FuncExprNode): + (JSC::FuncDeclNode::FuncDeclNode): + * parser/Nodes.cpp: + (JSC::ScopeNodeData::mark): + (JSC::FunctionBodyNode::finishParsing): + * parser/Nodes.h: + (JSC::FunctionBodyNode::ident): + Move m_ident & make methods from FuncDeclNode & FuncExprNode to FunctionBodyNode. + + * runtime/JSFunction.h: + (JSC::FunctionBodyNode::make): + Make this method inline (was FuncDeclNode::makeFunction). + +2009-08-11 Oliver Hunt <oliver@apple.com> + + Reviewed by Gavin Barraclough. + + Native JSON.stringify does not omit functions + https://bugs.webkit.org/show_bug.cgi?id=28117 + + Objects that are callable should be treated as undefined when + serialising to JSON. + + * runtime/JSONObject.cpp: + (JSC::Stringifier::appendStringifiedValue): + +2009-08-11 Oliver Hunt <oliver@apple.com> + + Reviewed by Geoff Garen. + + REGRESSION: Hang/crash in BytecodeGenerator::constRegisterFor loading simple page + https://bugs.webkit.org/show_bug.cgi?id=28169 + + Handle the case where someone has attempted to shadow a property + on the global object with a constant. + + * bytecompiler/BytecodeGenerator.cpp: + (JSC::BytecodeGenerator::constRegisterFor): + * parser/Nodes.cpp: + (JSC::ConstDeclNode::emitCodeSingle): + +2009-08-11 John Gregg <johnnyg@google.com> + + Reviewed by Maciej Stachowiak. + + Desktop Notifications API + https://bugs.webkit.org/show_bug.cgi?id=25463 + + Adds ENABLE_NOTIFICATION flag. + + * Configurations/FeatureDefines.xcconfig: + * wtf/Platform.h: + +2009-08-11 Maxime Simon <simon.maxime@gmail.com> + + Reviewed by Eric Seidel. + + Modifications on JavaScriptCore to allow Haiku port. + https://bugs.webkit.org/show_bug.cgi?id=28121 + + * runtime/Collector.cpp: Haiku doesn't have sys/mman.h, using OS.h instead. + (JSC::currentThreadStackBase): Haiku uses its own threading system. + * wtf/Platform.h: Defining all Haiku platform values. + * wtf/haiku/MainThreadHaiku.cpp: Adding a missing header (NotImplemented.h). + +2009-08-11 Jessie Berlin <jberlin@apple.com> + + Reviewed by Adam Roben. + + Fix windows build. + + * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def: + +2009-08-11 Csaba Osztrogonac <oszi@inf.u-szeged.hu> + + Reviewed by Tor Arne Vestbø. + + Buildfix for Qt-win platforms. + + * JavaScriptCore.pri: Choose MarkStackPosix.cpp or MarkStackWin.cpp depend on platform. + 2009-08-10 Oliver Hunt <oliver@apple.com> Reviewed by NOBODY (And another build fix). @@ -19,8 +8864,6 @@ 2009-08-10 Oliver Hunt <oliver@apple.com> - Reviewed by NOBODY (Build fix). - Add includes needed for non-allinonefile builds * runtime/GetterSetter.h: @@ -28,16 +8871,12 @@ 2009-08-10 Oliver Hunt <oliver@apple.com> - Reviewed by NOBODY (Build fix). - Fix export file for last build fix * JavaScriptCore.exp: 2009-08-10 Oliver Hunt <oliver@apple.com> - Reviewed by NOBODY (Build fix). - Hoist page size initialization into platform specific code. * jit/ExecutableAllocatorPosix.cpp: @@ -608,8 +9447,6 @@ 2009-08-04 Oliver Hunt <oliver@apple.com> - Reviewed by NOBODY (build fix). - PPC64 Build fix * wtf/Platform.h: @@ -864,8 +9701,6 @@ 2009-07-30 Gavin Barraclough <barraclough@apple.com> - Reviewed by NOBODY (build fix). - Temporarily revert r46618 since this is b0rking on Linux. 2009-07-23 Gavin Barraclough <barraclough@apple.com> @@ -3901,8 +12736,6 @@ 2009-07-20 Oliver Hunt <oliver@apple.com> - Reviewed by NOBODY (Build fix). - Build fix attempt #2 * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: @@ -3910,8 +12743,6 @@ 2009-07-20 Oliver Hunt <oliver@apple.com> - Reviewed by NOBODY (Build fix). - Build fix attempt #1 * JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def: @@ -4927,8 +13758,6 @@ 2009-07-09 Oliver Hunt <oliver@apple.com> - Reviewed by NOBODY (Build fix). - * interpreter/Interpreter.cpp: (JSC::Interpreter::privateExecute): @@ -5563,8 +14392,6 @@ 2009-06-21 Oliver Hunt <oliver@apple.com> - Reviewed by NOBODY (Build fix). - Remove dead code. * runtime/LiteralParser.cpp: diff --git a/JavaScriptCore/Configurations/Base.xcconfig b/JavaScriptCore/Configurations/Base.xcconfig index db89a7b..c338eb7 100644 --- a/JavaScriptCore/Configurations/Base.xcconfig +++ b/JavaScriptCore/Configurations/Base.xcconfig @@ -106,3 +106,4 @@ HAVE_DTRACE_macosx_ = $(HAVE_DTRACE_macosx_1040); HAVE_DTRACE_macosx_1040 = 0; HAVE_DTRACE_macosx_1050 = 0; HAVE_DTRACE_macosx_1060 = 1; +HAVE_DTRACE_macosx_1070 = 1; diff --git a/JavaScriptCore/Configurations/DebugRelease.xcconfig b/JavaScriptCore/Configurations/DebugRelease.xcconfig index 3b8651c..cbb0c8b 100644 --- a/JavaScriptCore/Configurations/DebugRelease.xcconfig +++ b/JavaScriptCore/Configurations/DebugRelease.xcconfig @@ -31,6 +31,7 @@ ARCHS_macosx_ = $(ARCHS_macosx_1040); ARCHS_macosx_1040 = $(NATIVE_ARCH); ARCHS_macosx_1050 = $(NATIVE_ARCH); ARCHS_macosx_1060 = $(ARCHS_STANDARD_32_64_BIT); +ARCHS_macosx_1070 = $(ARCHS_STANDARD_32_64_BIT); ONLY_ACTIVE_ARCH = YES; @@ -39,6 +40,7 @@ MACOSX_DEPLOYMENT_TARGET_ = 10.4; MACOSX_DEPLOYMENT_TARGET_1040 = 10.4; MACOSX_DEPLOYMENT_TARGET_1050 = 10.5; MACOSX_DEPLOYMENT_TARGET_1060 = 10.6; +MACOSX_DEPLOYMENT_TARGET_1070 = 10.7; GCC_WARN_ABOUT_DEPRECATED_FUNCTIONS = YES; diff --git a/JavaScriptCore/Configurations/FeatureDefines.xcconfig b/JavaScriptCore/Configurations/FeatureDefines.xcconfig index 10328e8..cd462d6 100644 --- a/JavaScriptCore/Configurations/FeatureDefines.xcconfig +++ b/JavaScriptCore/Configurations/FeatureDefines.xcconfig @@ -28,21 +28,30 @@ // Set any ENABLE_FEATURE_NAME macro to an empty string to disable that feature. +ENABLE_3D_CANVAS = $(ENABLE_3D_CANVAS_$(MAC_OS_X_VERSION_MAJOR)); +ENABLE_3D_CANVAS_1050 = ENABLE_3D_CANVAS; +ENABLE_3D_CANVAS_1060 = ENABLE_3D_CANVAS; +ENABLE_3D_CANVAS_1070 = ENABLE_3D_CANVAS; + ENABLE_3D_RENDERING = $(ENABLE_3D_RENDERING_$(MAC_OS_X_VERSION_MAJOR)); ENABLE_3D_RENDERING_1050 = ENABLE_3D_RENDERING; ENABLE_3D_RENDERING_1060 = ENABLE_3D_RENDERING; +ENABLE_3D_RENDERING_1070 = ENABLE_3D_RENDERING; ENABLE_CHANNEL_MESSAGING = ENABLE_CHANNEL_MESSAGING; ENABLE_DATABASE = ENABLE_DATABASE; ENABLE_DATAGRID = ENABLE_DATAGRID; +ENABLE_DATALIST = ENABLE_DATALIST; ENABLE_DOM_STORAGE = ENABLE_DOM_STORAGE; -ENABLE_FILTERS = ; +ENABLE_EVENTSOURCE = ENABLE_EVENTSOURCE; +ENABLE_FILTERS = ENABLE_FILTERS; ENABLE_GEOLOCATION = ; ENABLE_ICONDATABASE = ENABLE_ICONDATABASE; ENABLE_JAVASCRIPT_DEBUGGER = ENABLE_JAVASCRIPT_DEBUGGER; +ENABLE_MATHML = ; +ENABLE_NOTIFICATIONS = ; ENABLE_OFFLINE_WEB_APPLICATIONS = ENABLE_OFFLINE_WEB_APPLICATIONS; -ENABLE_RUBY = ENABLE_RUBY; -ENABLE_SHARED_WORKERS = ; +ENABLE_SHARED_WORKERS = ENABLE_SHARED_WORKERS; ENABLE_SVG = ENABLE_SVG; ENABLE_SVG_ANIMATION = ENABLE_SVG_ANIMATION; ENABLE_SVG_AS_IMAGE = ENABLE_SVG_AS_IMAGE; @@ -57,4 +66,4 @@ ENABLE_WORKERS = ENABLE_WORKERS; ENABLE_XPATH = ENABLE_XPATH; ENABLE_XSLT = ENABLE_XSLT; -FEATURE_DEFINES = $(ENABLE_3D_RENDERING) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_DATABASE) $(ENABLE_DATAGRID) $(ENABLE_DOM_STORAGE) $(ENABLE_FILTERS) $(ENABLE_GEOLOCATION) $(ENABLE_ICONDATABASE) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_OFFLINE_WEB_APPLICATIONS) $(ENABLE_RUBY) $(ENABLE_SHARED_WORKERS) $(ENABLE_SVG) $(ENABLE_SVG_ANIMATION) $(ENABLE_SVG_AS_IMAGE) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_SVG_FOREIGN_OBJECT) $(ENABLE_SVG_USE) $(ENABLE_VIDEO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WML) $(ENABLE_WORKERS) $(ENABLE_XPATH) $(ENABLE_XSLT); +FEATURE_DEFINES = $(ENABLE_3D_CANVAS) $(ENABLE_3D_RENDERING) $(ENABLE_CHANNEL_MESSAGING) $(ENABLE_DATABASE) $(ENABLE_DATAGRID) $(ENABLE_DATALIST) $(ENABLE_DOM_STORAGE) $(ENABLE_EVENTSOURCE) $(ENABLE_FILTERS) $(ENABLE_GEOLOCATION) $(ENABLE_ICONDATABASE) $(ENABLE_JAVASCRIPT_DEBUGGER) $(ENABLE_MATHML) $(ENABLE_NOTIFICATIONS) $(ENABLE_OFFLINE_WEB_APPLICATIONS) $(ENABLE_SHARED_WORKERS) $(ENABLE_SVG) $(ENABLE_SVG_ANIMATION) $(ENABLE_SVG_AS_IMAGE) $(ENABLE_SVG_DOM_OBJC_BINDINGS) $(ENABLE_SVG_FONTS) $(ENABLE_SVG_FOREIGN_OBJECT) $(ENABLE_SVG_USE) $(ENABLE_VIDEO) $(ENABLE_WEB_SOCKETS) $(ENABLE_WML) $(ENABLE_WORKERS) $(ENABLE_XPATH) $(ENABLE_XSLT); diff --git a/JavaScriptCore/Configurations/Version.xcconfig b/JavaScriptCore/Configurations/Version.xcconfig index d07d57f..b3bf41d 100644 --- a/JavaScriptCore/Configurations/Version.xcconfig +++ b/JavaScriptCore/Configurations/Version.xcconfig @@ -22,7 +22,7 @@ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. MAJOR_VERSION = 532; -MINOR_VERSION = 0; +MINOR_VERSION = 6; TINY_VERSION = 0; FULL_VERSION = $(MAJOR_VERSION).$(MINOR_VERSION); @@ -36,6 +36,7 @@ SYSTEM_VERSION_PREFIX_ = 4; // Some Tiger versions of Xcode don't set MAC_OS_X_V SYSTEM_VERSION_PREFIX_1040 = 4; SYSTEM_VERSION_PREFIX_1050 = 5; SYSTEM_VERSION_PREFIX_1060 = 6; +SYSTEM_VERSION_PREFIX_1070 = 7; // The production build always uses the full version with a system version prefix. BUNDLE_VERSION_Production = $(SYSTEM_VERSION_PREFIX)$(FULL_VERSION); diff --git a/JavaScriptCore/GNUmakefile.am b/JavaScriptCore/GNUmakefile.am index 6b4dc6d..dba305a 100644 --- a/JavaScriptCore/GNUmakefile.am +++ b/JavaScriptCore/GNUmakefile.am @@ -57,6 +57,7 @@ javascriptcore_sources += \ JavaScriptCore/API/JSClassRef.cpp \ JavaScriptCore/API/JSClassRef.h \ JavaScriptCore/API/JSContextRef.cpp \ + JavaScriptCore/API/JSContextRefPrivate.h \ JavaScriptCore/API/JSObjectRef.cpp \ JavaScriptCore/API/JSRetainPtr.h \ JavaScriptCore/API/JSStringRef.cpp \ @@ -96,8 +97,6 @@ javascriptcore_sources += \ JavaScriptCore/bytecode/JumpTable.cpp \ JavaScriptCore/bytecode/JumpTable.h \ JavaScriptCore/bytecode/EvalCodeCache.h \ - JavaScriptCore/runtime/ExceptionHelpers.cpp \ - JavaScriptCore/runtime/ExceptionHelpers.h \ JavaScriptCore/bytecode/Instruction.h \ JavaScriptCore/bytecompiler/Label.h \ JavaScriptCore/interpreter/Interpreter.cpp \ @@ -135,12 +134,17 @@ javascriptcore_sources += \ JavaScriptCore/icu/unicode/utf_old.h \ JavaScriptCore/icu/unicode/utypes.h \ JavaScriptCore/icu/unicode/uversion.h \ + JavaScriptCore/assembler/ARMAssembler.h \ + JavaScriptCore/assembler/ARMAssembler.cpp \ JavaScriptCore/assembler/X86Assembler.h \ JavaScriptCore/assembler/AbstractMacroAssembler.h \ JavaScriptCore/assembler/AssemblerBuffer.h \ + JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h \ JavaScriptCore/assembler/CodeLocation.h \ JavaScriptCore/assembler/LinkBuffer.h \ JavaScriptCore/assembler/MacroAssembler.h \ + JavaScriptCore/assembler/MacroAssemblerARM.h \ + JavaScriptCore/assembler/MacroAssemblerARM.cpp \ JavaScriptCore/assembler/MacroAssemblerCodeRef.h \ JavaScriptCore/assembler/MacroAssemblerX86.h \ JavaScriptCore/assembler/MacroAssemblerX86_64.h \ @@ -173,8 +177,10 @@ javascriptcore_sources += \ JavaScriptCore/interpreter/CallFrame.cpp \ JavaScriptCore/interpreter/CallFrame.h \ JavaScriptCore/interpreter/CallFrameClosure.h \ - JavaScriptCore/runtime/TimeoutChecker.cpp \ - JavaScriptCore/runtime/TimeoutChecker.h \ + JavaScriptCore/runtime/ExceptionHelpers.cpp \ + JavaScriptCore/runtime/ExceptionHelpers.h \ + JavaScriptCore/runtime/Executable.cpp \ + JavaScriptCore/runtime/Executable.h \ JavaScriptCore/runtime/InitializeThreading.cpp \ JavaScriptCore/runtime/InitializeThreading.h \ JavaScriptCore/runtime/JSActivation.cpp \ @@ -193,7 +199,9 @@ javascriptcore_sources += \ JavaScriptCore/runtime/LiteralParser.h \ JavaScriptCore/runtime/MarkStack.cpp \ JavaScriptCore/runtime/MarkStack.h \ - JavaScriptCore/runtime/MarkStackPosix.cpp \ + JavaScriptCore/runtime/NumericStrings.h \ + JavaScriptCore/runtime/PropertyDescriptor.h \ + JavaScriptCore/runtime/PropertyDescriptor.cpp \ JavaScriptCore/runtime/SmallStrings.cpp \ JavaScriptCore/runtime/SmallStrings.h \ JavaScriptCore/runtime/Structure.cpp \ @@ -201,7 +209,9 @@ javascriptcore_sources += \ JavaScriptCore/runtime/StructureChain.cpp \ JavaScriptCore/runtime/StructureChain.h \ JavaScriptCore/runtime/StructureTransitionTable.h \ - JavaScriptCore/runtime/TypeInfo.h \ + JavaScriptCore/runtime/TimeoutChecker.cpp \ + JavaScriptCore/runtime/TimeoutChecker.h \ + JavaScriptCore/runtime/JSTypeInfo.h \ JavaScriptCore/wrec/CharacterClass.h \ JavaScriptCore/wrec/CharacterClassConstructor.h \ JavaScriptCore/wrec/Escapes.h \ @@ -226,8 +236,6 @@ javascriptcore_sources += \ JavaScriptCore/wtf/Deque.h \ JavaScriptCore/wtf/DisallowCType.h \ JavaScriptCore/wtf/Forward.h \ - JavaScriptCore/wtf/GOwnPtr.cpp \ - JavaScriptCore/wtf/GOwnPtr.h \ JavaScriptCore/wtf/GetPtr.h \ JavaScriptCore/wtf/HashCountedSet.h \ JavaScriptCore/wtf/HashFunctions.h \ @@ -252,6 +260,7 @@ javascriptcore_sources += \ JavaScriptCore/wtf/PassOwnPtr.h \ JavaScriptCore/wtf/PassRefPtr.h \ JavaScriptCore/wtf/Platform.h \ + JavaScriptCore/wtf/PossiblyNull.h \ JavaScriptCore/wtf/PtrAndFlags.h \ JavaScriptCore/wtf/RandomNumber.cpp \ JavaScriptCore/wtf/RandomNumber.h \ @@ -277,6 +286,8 @@ javascriptcore_sources += \ JavaScriptCore/wtf/UnusedParam.h \ JavaScriptCore/wtf/Vector.h \ JavaScriptCore/wtf/VectorTraits.h \ + JavaScriptCore/wtf/gtk/GOwnPtr.cpp \ + JavaScriptCore/wtf/gtk/GOwnPtr.h \ JavaScriptCore/wtf/gtk/MainThreadGtk.cpp \ JavaScriptCore/wtf/gtk/ThreadingGtk.cpp \ JavaScriptCore/wtf/unicode/Collator.h \ @@ -288,10 +299,12 @@ javascriptcore_sources += \ if TARGET_WIN32 javascriptcore_sources += \ JavaScriptCore/wtf/ThreadSpecificWin.cpp \ - JavaScriptCore/jit/ExecutableAllocatorWin.cpp + JavaScriptCore/jit/ExecutableAllocatorWin.cpp \ + JavaScriptCore/runtime/MarkStackWin.cpp else javascriptcore_sources += \ - JavaScriptCore/jit/ExecutableAllocatorPosix.cpp + JavaScriptCore/jit/ExecutableAllocatorPosix.cpp \ + JavaScriptCore/runtime/MarkStackPosix.cpp endif # ---- @@ -324,17 +337,12 @@ javascriptcore_sources += \ JavaScriptCore/yarr/RegexParser.h \ JavaScriptCore/yarr/RegexPattern.h -# Debug build -if ENABLE_DEBUG -javascriptcore_built_sources += \ - DerivedSources/Grammar.cpp \ - DerivedSources/Grammar.h - javascriptcore_sources += \ JavaScriptCore/interpreter/RegisterFile.cpp \ JavaScriptCore/interpreter/RegisterFile.h \ JavaScriptCore/bytecompiler/BytecodeGenerator.cpp \ JavaScriptCore/bytecompiler/BytecodeGenerator.h \ + JavaScriptCore/bytecompiler/NodesCodegen.cpp \ JavaScriptCore/bytecompiler/LabelScope.h \ JavaScriptCore/debugger/Debugger.cpp \ JavaScriptCore/debugger/Debugger.h \ @@ -383,6 +391,7 @@ javascriptcore_sources += \ JavaScriptCore/runtime/DateConversion.h \ JavaScriptCore/runtime/DateInstance.cpp \ JavaScriptCore/runtime/DateInstance.h \ + JavaScriptCore/runtime/DateInstanceCache.h \ JavaScriptCore/runtime/DatePrototype.cpp \ JavaScriptCore/runtime/DatePrototype.h \ JavaScriptCore/runtime/Error.cpp \ @@ -439,9 +448,6 @@ javascriptcore_sources += \ JavaScriptCore/runtime/JSWrapperObject.h \ JavaScriptCore/runtime/Lookup.cpp \ JavaScriptCore/runtime/Lookup.h \ - JavaScriptCore/runtime/MarkStack.cpp \ - JavaScriptCore/runtime/MarkStack.h \ - JavaScriptCore/runtime/MarkStackWin.cpp \ JavaScriptCore/runtime/MathObject.cpp \ JavaScriptCore/runtime/MathObject.h \ JavaScriptCore/runtime/NativeErrorConstructor.cpp \ @@ -493,6 +499,7 @@ javascriptcore_sources += \ JavaScriptCore/runtime/Tracing.h \ JavaScriptCore/runtime/UString.cpp \ JavaScriptCore/runtime/UString.h \ + JavaScriptCore/runtime/WeakRandom.h \ JavaScriptCore/wtf/FastAllocBase.h \ JavaScriptCore/wtf/FastMalloc.cpp \ JavaScriptCore/wtf/FastMalloc.h \ @@ -502,17 +509,10 @@ javascriptcore_sources += \ JavaScriptCore/wtf/dtoa.cpp \ JavaScriptCore/wtf/dtoa.h -else -javascriptcore_built_nosources += \ +javascriptcore_built_sources += \ DerivedSources/Grammar.cpp \ DerivedSources/Grammar.h -javascriptcore_sources += \ - JavaScriptCore/AllInOneFile.cpp \ - JavaScriptCore/parser/ParserArena.cpp \ - JavaScriptCore/parser/ParserArena.h -endif # END ENABLE_DEBUG - DerivedSources/Grammar.h: DerivedSources/Grammar.cpp; DerivedSources/Grammar.cpp: $(srcdir)/JavaScriptCore/parser/Grammar.y diff --git a/JavaScriptCore/JavaScriptCore.exp b/JavaScriptCore/JavaScriptCore.exp index 3a2acd7..1c91d36 100644 --- a/JavaScriptCore/JavaScriptCore.exp +++ b/JavaScriptCore/JavaScriptCore.exp @@ -2,6 +2,7 @@ _JSCheckScriptSyntax _JSClassCreate _JSClassRelease _JSClassRetain +_JSContextGetGlobalContext _JSContextGetGlobalObject _JSContextGetGroup _JSContextGroupCreate @@ -95,87 +96,98 @@ __ZN3JSC10Identifier24checkSameIdentifierTableEPNS_12JSGlobalDataEPNS_7UString3R __ZN3JSC10Identifier24checkSameIdentifierTableEPNS_9ExecStateEPNS_7UString3RepE __ZN3JSC10Identifier3addEPNS_9ExecStateEPKc __ZN3JSC10Identifier5equalEPKNS_7UString3RepEPKc -__ZN3JSC10JSFunction4infoE -__ZN3JSC10JSFunctionC1EPNS_9ExecStateEN3WTF10PassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectESA_RKNS_7ArgListEE +__ZN3JSC10JSFunctionC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectESA_RKNS_7ArgListEE __ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeE __ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeEPKc __ZN3JSC10throwErrorEPNS_9ExecStateENS_9ErrorTypeERKNS_7UStringE __ZN3JSC11JSByteArray15createStructureENS_7JSValueE -__ZN3JSC11JSByteArrayC1EPNS_9ExecStateEN3WTF10PassRefPtrINS_9StructureEEEPNS3_9ByteArrayEPKNS_9ClassInfoE +__ZN3JSC11JSByteArrayC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEPNS3_9ByteArrayEPKNS_9ClassInfoE __ZN3JSC11ParserArena5resetEv __ZN3JSC11checkSyntaxEPNS_9ExecStateERKNS_10SourceCodeE __ZN3JSC12DateInstance4infoE +__ZN3JSC12DateInstanceC1EPNS_9ExecStateEd __ZN3JSC12JSGlobalData10ClientDataD2Ev __ZN3JSC12JSGlobalData12createLeakedEv +__ZN3JSC12JSGlobalData12stopSamplingEv +__ZN3JSC12JSGlobalData13startSamplingEv +__ZN3JSC12JSGlobalData14dumpSampleDataEPNS_9ExecStateE +__ZN3JSC12JSGlobalData14resetDateCacheEv __ZN3JSC12JSGlobalData14sharedInstanceEv __ZN3JSC12JSGlobalData6createEb __ZN3JSC12JSGlobalDataD1Ev -__ZN3JSC12SamplingTool4dumpEPNS_9ExecStateE __ZN3JSC12SamplingTool5setupEv __ZN3JSC12SmallStrings17createEmptyStringEPNS_12JSGlobalDataE +__ZN3JSC12SmallStrings27createSingleCharacterStringEPNS_12JSGlobalDataEh __ZN3JSC12StringObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE -__ZN3JSC12StringObject14toThisJSStringEPNS_9ExecStateE -__ZN3JSC12StringObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE __ZN3JSC12StringObject18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE __ZN3JSC12StringObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE +__ZN3JSC12StringObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE +__ZN3JSC12StringObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE __ZN3JSC12StringObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE __ZN3JSC12StringObject4infoE -__ZN3JSC12StringObjectC2EPNS_9ExecStateEN3WTF10PassRefPtrINS_9StructureEEERKNS_7UStringE +__ZN3JSC12StringObjectC2EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_7UStringE __ZN3JSC12jsNumberCellEPNS_9ExecStateEd __ZN3JSC12nonInlineNaNEv __ZN3JSC13SamplingFlags4stopEv __ZN3JSC13SamplingFlags5startEv __ZN3JSC13SamplingFlags7s_flagsE __ZN3JSC13StatementNode6setLocEii -__ZN3JSC13jsOwnedStringEPNS_12JSGlobalDataERKNS_7UStringE __ZN3JSC14JSGlobalObject10globalExecEv -__ZN3JSC14JSGlobalObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectE -__ZN3JSC14JSGlobalObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectE +__ZN3JSC14JSGlobalObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectEj +__ZN3JSC14JSGlobalObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPNS_8JSObjectEj __ZN3JSC14JSGlobalObject12markChildrenERNS_9MarkStackE __ZN3JSC14JSGlobalObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj +__ZN3JSC14JSGlobalObject25destroyJSGlobalObjectDataEPv __ZN3JSC14JSGlobalObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE __ZN3JSC14JSGlobalObject4initEPNS_8JSObjectE __ZN3JSC14JSGlobalObjectD2Ev __ZN3JSC14JSGlobalObjectnwEmPNS_12JSGlobalDataE __ZN3JSC14SamplingThread4stopEv __ZN3JSC14SamplingThread5startEj +__ZN3JSC14TimeoutChecker10didTimeOutEPNS_9ExecStateE __ZN3JSC14TimeoutChecker5resetEv -__ZN3JSC14constructArrayEPNS_9ExecStateERKNS_7ArgListE __ZN3JSC15JSWrapperObject12markChildrenERNS_9MarkStackE +__ZN3JSC15createTypeErrorEPNS_9ExecStateEPKc __ZN3JSC15toInt32SlowCaseEdRb -__ZN3JSC16FunctionBodyNode13finishParsingEPNS_10IdentifierEm -__ZN3JSC16FunctionBodyNode14copyParametersEv -__ZN3JSC16FunctionBodyNode6createEPNS_12JSGlobalDataEPNS_14SourceElementsEPN3WTF6VectorISt4pairINS_10IdentifierEjELm0EEEPNS6_IPNS_12FuncDeclNodeELm0EEERKNS_10SourceCodeEji __ZN3JSC16InternalFunction4infoE -__ZN3JSC16InternalFunction4nameEPNS_12JSGlobalDataE -__ZN3JSC16InternalFunctionC2EPNS_12JSGlobalDataEN3WTF10PassRefPtrINS_9StructureEEERKNS_10IdentifierE +__ZN3JSC16InternalFunction4nameEPNS_9ExecStateE +__ZN3JSC16InternalFunctionC2EPNS_12JSGlobalDataEN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_10IdentifierE __ZN3JSC16JSVariableObject14deletePropertyEPNS_9ExecStateERKNS_10IdentifierE -__ZN3JSC16JSVariableObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE +__ZN3JSC16JSVariableObject14symbolTableGetERKNS_10IdentifierERNS_18PropertyDescriptorE +__ZN3JSC16JSVariableObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE __ZN3JSC16toUInt32SlowCaseEdRb __ZN3JSC17BytecodeGenerator21setDumpsGeneratedCodeEb __ZN3JSC17PropertyNameArray3addEPNS_7UString3RepE -__ZN3JSC17PrototypeFunctionC1EPNS_9ExecStateEN3WTF10PassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectESA_RKNS_7ArgListEE +__ZN3JSC17PrototypeFunctionC1EPNS_9ExecStateEN3WTF17NonNullPassRefPtrINS_9StructureEEEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectESA_RKNS_7ArgListEE __ZN3JSC17PrototypeFunctionC1EPNS_9ExecStateEiRKNS_10IdentifierEPFNS_7JSValueES2_PNS_8JSObjectES6_RKNS_7ArgListEE __ZN3JSC17constructFunctionEPNS_9ExecStateERKNS_7ArgListERKNS_10IdentifierERKNS_7UStringEi __ZN3JSC18DebuggerActivationC1EPNS_8JSObjectE -__ZN3JSC19constructEmptyArrayEPNS_9ExecStateE +__ZN3JSC18PropertyDescriptor11setWritableEb +__ZN3JSC18PropertyDescriptor12setUndefinedEv +__ZN3JSC18PropertyDescriptor13setDescriptorENS_7JSValueEj +__ZN3JSC18PropertyDescriptor13setEnumerableEb +__ZN3JSC18PropertyDescriptor15setConfigurableEb +__ZN3JSC18PropertyDescriptor17defaultAttributesE +__ZN3JSC18PropertyDescriptor21setAccessorDescriptorENS_7JSValueES1_j +__ZN3JSC18PropertyDescriptor9setGetterENS_7JSValueE +__ZN3JSC18PropertyDescriptor9setSetterENS_7JSValueE __ZN3JSC19initializeThreadingEv __ZN3JSC20MarkedArgumentBuffer10slowAppendENS_7JSValueE -__ZN3JSC20constructEmptyObjectEPNS_9ExecStateE __ZN3JSC23AbstractSamplingCounter4dumpEv __ZN3JSC23objectProtoFuncToStringEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE __ZN3JSC23setUpStaticFunctionSlotEPNS_9ExecStateEPKNS_9HashEntryEPNS_8JSObjectERKNS_10IdentifierERNS_12PropertySlotE +__ZN3JSC24createStackOverflowErrorEPNS_9ExecStateE __ZN3JSC25evaluateInGlobalCallFrameERKNS_7UStringERNS_7JSValueEPNS_14JSGlobalObjectE +__ZN3JSC35createInterruptedExecutionExceptionEPNS_12JSGlobalDataE +__ZN3JSC3NaNE __ZN3JSC4Heap11objectCountEv __ZN3JSC4Heap14primaryHeapEndEv __ZN3JSC4Heap15recordExtraCostEm __ZN3JSC4Heap16primaryHeapBeginEv __ZN3JSC4Heap17globalObjectCountEv __ZN3JSC4Heap20protectedObjectCountEv -__ZN3JSC4Heap24setGCProtectNeedsLockingEv __ZN3JSC4Heap25protectedObjectTypeCountsEv __ZN3JSC4Heap26protectedGlobalObjectCountEv -__ZN3JSC4Heap4heapENS_7JSValueE __ZN3JSC4Heap6isBusyEv __ZN3JSC4Heap7collectEv __ZN3JSC4Heap7destroyEv @@ -192,12 +204,13 @@ __ZN3JSC6JSCell14toThisJSStringEPNS_9ExecStateE __ZN3JSC6JSCell16getConstructDataERNS_13ConstructDataE __ZN3JSC6JSCell18getOwnPropertySlotEPNS_9ExecStateERKNS_10IdentifierERNS_12PropertySlotE __ZN3JSC6JSCell18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE +__ZN3JSC6JSCell18getPrimitiveNumberEPNS_9ExecStateERdRNS_7JSValueE __ZN3JSC6JSCell3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE __ZN3JSC6JSCell3putEPNS_9ExecStateEjNS_7JSValueE __ZN3JSC6JSCell9getObjectEv __ZN3JSC6JSCellnwEmPNS_9ExecStateE -__ZN3JSC6JSLock12DropAllLocksC1EPNS_9ExecStateE __ZN3JSC6JSLock12DropAllLocksC1ENS_14JSLockBehaviorE +__ZN3JSC6JSLock12DropAllLocksC1EPNS_9ExecStateE __ZN3JSC6JSLock12DropAllLocksD1Ev __ZN3JSC6JSLock4lockENS_14JSLockBehaviorE __ZN3JSC6JSLock6unlockENS_14JSLockBehaviorE @@ -207,6 +220,9 @@ __ZN3JSC6Parser5parseEPNS_12JSGlobalDataEPiPNS_7UStringE __ZN3JSC7CStringD1Ev __ZN3JSC7CStringaSERKS0_ __ZN3JSC7JSArray4infoE +__ZN3JSC7JSArray9setLengthEj +__ZN3JSC7JSArrayC1EN3WTF17NonNullPassRefPtrINS_9StructureEEE +__ZN3JSC7JSArrayC1EN3WTF17NonNullPassRefPtrINS_9StructureEEERKNS_7ArgListE __ZN3JSC7Profile10restoreAllEv __ZN3JSC7Profile5focusEPKNS_11ProfileNodeE __ZN3JSC7Profile7excludeEPKNS_11ProfileNodeE @@ -227,13 +243,13 @@ __ZN3JSC7UString6appendERKS0_ __ZN3JSC7UStringC1EPKc __ZN3JSC7UStringC1EPKti __ZN3JSC7UStringaSEPKc +__ZN3JSC8Debugger23recompileAllJSFunctionsEPNS_12JSGlobalDataE __ZN3JSC8Debugger6attachEPNS_14JSGlobalObjectE __ZN3JSC8Debugger6detachEPNS_14JSGlobalObjectE -__ZN3JSC8DebuggerC2Ev __ZN3JSC8DebuggerD2Ev __ZN3JSC8JSObject11hasInstanceEPNS_9ExecStateENS_7JSValueES3_ -__ZN3JSC8JSObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPS0_ -__ZN3JSC8JSObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPS0_ +__ZN3JSC8JSObject12defineGetterEPNS_9ExecStateERKNS_10IdentifierEPS0_j +__ZN3JSC8JSObject12defineSetterEPNS_9ExecStateERKNS_10IdentifierEPS0_j __ZN3JSC8JSObject12lookupGetterEPNS_9ExecStateERKNS_10IdentifierE __ZN3JSC8JSObject12lookupSetterEPNS_9ExecStateERKNS_10IdentifierE __ZN3JSC8JSObject12markChildrenERNS_9MarkStackE @@ -242,32 +258,38 @@ __ZN3JSC8JSObject14deletePropertyEPNS_9ExecStateEj __ZN3JSC8JSObject15unwrappedObjectEv __ZN3JSC8JSObject16getPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE __ZN3JSC8JSObject17createInheritorIDEv +__ZN3JSC8JSObject17defineOwnPropertyEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorEb __ZN3JSC8JSObject17putDirectFunctionEPNS_9ExecStateEPNS_16InternalFunctionEj __ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEj __ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueEjbRNS_15PutPropertySlotE __ZN3JSC8JSObject17putWithAttributesEPNS_9ExecStateEjNS_7JSValueEj __ZN3JSC8JSObject18getOwnPropertySlotEPNS_9ExecStateEjRNS_12PropertySlotE __ZN3JSC8JSObject18getPrimitiveNumberEPNS_9ExecStateERdRNS_7JSValueE +__ZN3JSC8JSObject19getOwnPropertyNamesEPNS_9ExecStateERNS_17PropertyNameArrayE +__ZN3JSC8JSObject21getPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE __ZN3JSC8JSObject22fillGetterPropertySlotERNS_12PropertySlotEPNS_7JSValueE __ZN3JSC8JSObject23allocatePropertyStorageEmm +__ZN3JSC8JSObject24getOwnPropertyDescriptorEPNS_9ExecStateERKNS_10IdentifierERNS_18PropertyDescriptorE __ZN3JSC8JSObject3putEPNS_9ExecStateERKNS_10IdentifierENS_7JSValueERNS_15PutPropertySlotE __ZN3JSC8JSObject3putEPNS_9ExecStateEjNS_7JSValueE +__ZN3JSC8JSString4RopeD1Ev __ZN3JSC8Profiler13stopProfilingEPNS_9ExecStateERKNS_7UStringE __ZN3JSC8Profiler14startProfilingEPNS_9ExecStateERKNS_7UStringE __ZN3JSC8Profiler8profilerEv __ZN3JSC8evaluateEPNS_9ExecStateERNS_10ScopeChainERKNS_10SourceCodeENS_7JSValueE -__ZN3JSC8jsStringEPNS_12JSGlobalDataERKNS_7UStringE __ZN3JSC9CodeBlockD1Ev __ZN3JSC9CodeBlockD2Ev __ZN3JSC9MarkStack10s_pageSizeE __ZN3JSC9MarkStack12releaseStackEPvm __ZN3JSC9MarkStack13allocateStackEm __ZN3JSC9MarkStack18initializePagesizeEv +__ZN3JSC9Structure13hasTransitionEPNS_7UString3RepEj __ZN3JSC9Structure17stopIgnoringLeaksEv __ZN3JSC9Structure18startIgnoringLeaksEv __ZN3JSC9Structure21addPropertyTransitionEPS0_RKNS_10IdentifierEjPNS_6JSCellERm __ZN3JSC9Structure22materializePropertyMapEv __ZN3JSC9Structure25changePrototypeTransitionEPS0_NS_7JSValueE +__ZN3JSC9Structure27addAnonymousSlotsTransitionEPS0_j __ZN3JSC9Structure27despecifyDictionaryFunctionERKNS_10IdentifierE __ZN3JSC9Structure27despecifyFunctionTransitionEPS0_RKNS_10IdentifierE __ZN3JSC9Structure28addPropertyWithoutTransitionERKNS_10IdentifierEjPNS_6JSCellE @@ -290,6 +312,7 @@ __ZN3WTF12isMainThreadEv __ZN3WTF12randomNumberEv __ZN3WTF13currentThreadEv __ZN3WTF13tryFastCallocEmm +__ZN3WTF13tryFastMallocEm __ZN3WTF15ThreadCondition4waitERNS_5MutexE __ZN3WTF15ThreadCondition6signalEv __ZN3WTF15ThreadCondition9broadcastEv @@ -306,9 +329,11 @@ __ZN3WTF21RefCountedLeakCounter9decrementEv __ZN3WTF21RefCountedLeakCounter9incrementEv __ZN3WTF21RefCountedLeakCounterC1EPKc __ZN3WTF21RefCountedLeakCounterD1Ev +__ZN3WTF23callOnMainThreadAndWaitEPFvPvES0_ __ZN3WTF23waitForThreadCompletionEjPPv __ZN3WTF27releaseFastMallocFreeMemoryEv __ZN3WTF28setMainThreadCallbacksPausedEb +__ZN3WTF32doubleToStringInJavaScriptFormatEdPcPj __ZN3WTF36lockAtomicallyInitializedStaticMutexEv __ZN3WTF37parseDateFromNullTerminatedCharactersEPKc __ZN3WTF38unlockAtomicallyInitializedStaticMutexEv @@ -324,30 +349,37 @@ __ZN3WTF8CollatorC1EPKc __ZN3WTF8CollatorD1Ev __ZN3WTF8fastFreeEPv __ZN3WTF9ByteArray6createEm +__ZNK3JSC10JSFunction23isHostFunctionNonInlineEv __ZNK3JSC11Interpreter14retrieveCallerEPNS_9ExecStateEPNS_16InternalFunctionE __ZNK3JSC11Interpreter18retrieveLastCallerEPNS_9ExecStateERiRlRNS_7UStringERNS_7JSValueE -__ZNK3JSC12DateInstance7getTimeERdRi -__ZNK3JSC12StringObject12toThisStringEPNS_9ExecStateE -__ZNK3JSC12StringObject8toStringEPNS_9ExecStateE __ZNK3JSC14JSGlobalObject14isDynamicScopeEv - -__ZNK3JSC16FunctionBodyNode14isHostFunctionEv __ZNK3JSC16InternalFunction9classInfoEv __ZNK3JSC16JSVariableObject16isVariableObjectEv -__ZNK3JSC16JSVariableObject21getPropertyAttributesEPNS_9ExecStateERKNS_10IdentifierERj __ZNK3JSC17DebuggerCallFrame10thisObjectEv __ZNK3JSC17DebuggerCallFrame12functionNameEv __ZNK3JSC17DebuggerCallFrame22calculatedFunctionNameEv __ZNK3JSC17DebuggerCallFrame4typeEv __ZNK3JSC17DebuggerCallFrame8evaluateERKNS_7UStringERNS_7JSValueE +__ZNK3JSC18PropertyDescriptor10enumerableEv +__ZNK3JSC18PropertyDescriptor12configurableEv +__ZNK3JSC18PropertyDescriptor16isDataDescriptorEv +__ZNK3JSC18PropertyDescriptor20isAccessorDescriptorEv +__ZNK3JSC18PropertyDescriptor6getterEv +__ZNK3JSC18PropertyDescriptor6setterEv +__ZNK3JSC18PropertyDescriptor8writableEv __ZNK3JSC4Heap10statisticsEv +__ZNK3JSC6JSCell11toPrimitiveEPNS_9ExecStateENS_22PreferredPrimitiveTypeE __ZNK3JSC6JSCell12toThisObjectEPNS_9ExecStateE __ZNK3JSC6JSCell12toThisStringEPNS_9ExecStateE __ZNK3JSC6JSCell14isGetterSetterEv +__ZNK3JSC6JSCell8toNumberEPNS_9ExecStateE +__ZNK3JSC6JSCell8toObjectEPNS_9ExecStateE +__ZNK3JSC6JSCell8toStringEPNS_9ExecStateE __ZNK3JSC6JSCell9classInfoEv -__ZNK3JSC6JSCell9getStringERNS_7UStringE -__ZNK3JSC6JSCell9getStringEv __ZNK3JSC6JSCell9getUInt32ERj +__ZNK3JSC6JSCell9getStringEPNS_9ExecStateE +__ZNK3JSC6JSCell9getStringEPNS_9ExecStateERNS_7UStringE +__ZNK3JSC6JSCell9toBooleanEPNS_9ExecStateE __ZNK3JSC7ArgList8getSliceEiRS0_ __ZNK3JSC7JSValue16toObjectSlowCaseEPNS_9ExecStateE __ZNK3JSC7JSValue19synthesizePrototypeEPNS_9ExecStateE @@ -364,12 +396,12 @@ __ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateERKNS_10IdentifierE __ZNK3JSC8JSObject11hasPropertyEPNS_9ExecStateEj __ZNK3JSC8JSObject12defaultValueEPNS_9ExecStateENS_22PreferredPrimitiveTypeE __ZNK3JSC8JSObject12toThisObjectEPNS_9ExecStateE -__ZNK3JSC8JSObject21getPropertyAttributesEPNS_9ExecStateERKNS_10IdentifierERj __ZNK3JSC8JSObject8toNumberEPNS_9ExecStateE __ZNK3JSC8JSObject8toObjectEPNS_9ExecStateE __ZNK3JSC8JSObject8toStringEPNS_9ExecStateE __ZNK3JSC8JSObject9classNameEv __ZNK3JSC8JSObject9toBooleanEPNS_9ExecStateE +__ZNK3JSC8JSString11resolveRopeEPNS_9ExecStateE __ZNK3JSC9HashTable11createTableEPNS_12JSGlobalDataE __ZNK3JSC9HashTable11deleteTableEv __ZNK3WTF8Collator7collateEPKtmS2_m @@ -378,7 +410,7 @@ __ZTVN3JSC14JSGlobalObjectE __ZTVN3JSC15JSWrapperObjectE __ZTVN3JSC16InternalFunctionE __ZTVN3JSC16JSVariableObjectE -__ZTVN3JSC17JSAPIValueWrapperE +__ZTVN3JSC8DebuggerE __ZTVN3JSC8JSObjectE __ZTVN3JSC8JSStringE _jscore_fastmalloc_introspection diff --git a/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp b/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp new file mode 100644 index 0000000..64e20a2 --- /dev/null +++ b/JavaScriptCore/JavaScriptCore.gyp/JavaScriptCore.gyp @@ -0,0 +1,190 @@ +# +# Copyright (C) 2009 Google Inc. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions are +# met: +# +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above +# copyright notice, this list of conditions and the following disclaimer +# in the documentation and/or other materials provided with the +# distribution. +# * Neither the name of Google Inc. nor the names of its +# contributors may be used to endorse or promote products derived from +# this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +# "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +# LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +# A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +# OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +# SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +# LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +# THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +# + +{ + 'includes': [ + # FIXME: Sense whether upstream or downstream build, and + # include the right features.gypi + '../../WebKit/chromium/features.gypi', + '../JavaScriptCore.gypi', + ], + 'variables': { + # Location of the chromium src directory. + 'conditions': [ + ['inside_chromium_build==0', { + # Webkit is being built outside of the full chromium project. + 'chromium_src_dir': '../../WebKit/chromium', + },{ + # WebKit is checked out in src/chromium/third_party/WebKit + 'chromium_src_dir': '../../../..', + }], + ], + }, + 'targets': [ + { + # This target sets up defines and includes that are required by WTF and + # its dependents. + 'target_name': 'wtf_config', + 'type': 'none', + 'msvs_guid': '2E2D3301-2EC4-4C0F-B889-87073B30F673', + 'direct_dependent_settings': { + 'defines': [ + # Import features_defines from features.gypi + '<@(feature_defines)', + + # Turns on #if PLATFORM(CHROMIUM) + 'BUILDING_CHROMIUM__=1', + # Controls wtf/FastMalloc + # FIXME: consider moving into config.h + 'USE_SYSTEM_MALLOC=1', + ], + 'conditions': [ + ['OS=="win"', { + 'defines': [ + '__STD_C', + '_CRT_SECURE_NO_DEPRECATE', + '_SCL_SECURE_NO_DEPRECATE', + 'CRASH=__debugbreak', + ], + 'include_dirs': [ + '../os-win32', + ], + }], + ['OS=="mac"', { + 'defines': [ + # Use USE_NEW_THEME on Mac. + 'WTF_USE_NEW_THEME=1', + ], + }], + ['OS=="linux" or OS=="freebsd"', { + 'defines': [ + 'WTF_USE_PTHREADS=1', + ], + }], + ], + } + }, + { + 'target_name': 'wtf', + 'type': '<(library)', + 'msvs_guid': 'AA8A5A85-592B-4357-BC60-E0E91E026AF6', + 'dependencies': [ + 'wtf_config', + '<(chromium_src_dir)/third_party/icu/icu.gyp:icui18n', + '<(chromium_src_dir)/third_party/icu/icu.gyp:icuuc', + ], + 'include_dirs': [ + '../', + '../wtf', + '../wtf/unicode', + ], + 'sources': [ + '<@(javascriptcore_files)', + ], + 'sources/': [ + # First exclude everything ... + ['exclude', '../'], + # ... Then include what we want. + ['include', '../wtf/'], + # GLib/GTK, even though its name doesn't really indicate. + ['exclude', '/(gtk|glib)/.*\\.(cpp|h)$'], + ['exclude', '(Default|Gtk|Mac|None|Qt|Win|Wx)\\.(cpp|mm)$'], + ['exclude', 'wtf/CurrentTime\\.cpp$'], + ['exclude', 'wtf/TC.*\\.(cpp|h)$'], + ], + 'direct_dependent_settings': { + 'include_dirs': [ + '../', + '../wtf', + ], + }, + 'export_dependent_settings': [ + 'wtf_config', + '<(chromium_src_dir)/third_party/icu/icu.gyp:icui18n', + '<(chromium_src_dir)/third_party/icu/icu.gyp:icuuc', + ], + 'msvs_disabled_warnings': [4127, 4355, 4510, 4512, 4610, 4706], + 'conditions': [ + ['OS=="win"', { + 'sources/': [ + ['exclude', 'ThreadingPthreads\\.cpp$'], + ['include', 'Thread(ing|Specific)Win\\.cpp$'] + ], + 'include_dirs!': [ + '<(SHARED_INTERMEDIATE_DIR)/webkit', + ], + }], + ], + }, + { + 'target_name': 'pcre', + 'type': '<(library)', + 'dependencies': [ + 'wtf', + ], + 'conditions': [ + ['OS=="win"', { + 'dependencies': ['<(chromium_src_dir)/build/win/system.gyp:cygwin'], + }], + ], + 'msvs_guid': '49909552-0B0C-4C14-8CF6-DB8A2ADE0934', + 'actions': [ + { + 'action_name': 'dftables', + 'inputs': [ + '../pcre/dftables', + ], + 'outputs': [ + '<(INTERMEDIATE_DIR)/chartables.c', + ], + 'action': ['perl', '-w', '<@(_inputs)', '<@(_outputs)'], + }, + ], + 'include_dirs': [ + '<(INTERMEDIATE_DIR)', + ], + 'sources': [ + '<@(javascriptcore_files)', + ], + 'sources/': [ + # First exclude everything ... + ['exclude', '../'], + # ... Then include what we want. + ['include', '../pcre/'], + # ucptable.cpp is #included by pcre_ucp_searchfunchs.cpp and is not + # intended to be compiled directly. + ['exclude', '../pcre/ucptable.cpp$'], + ], + 'export_dependent_settings': [ + 'wtf', + ], + }, + ], # targets +} diff --git a/JavaScriptCore/JavaScriptCore.gypi b/JavaScriptCore/JavaScriptCore.gypi index 462c38f..b4495b2 100644 --- a/JavaScriptCore/JavaScriptCore.gypi +++ b/JavaScriptCore/JavaScriptCore.gypi @@ -1,7 +1,6 @@ { 'variables': { 'javascriptcore_files': [ - 'AllInOneFile.cpp', 'API/APICast.h', 'API/JavaScript.h', 'API/JavaScriptCore.h', @@ -19,6 +18,7 @@ 'API/JSClassRef.h', 'API/JSContextRef.cpp', 'API/JSContextRef.h', + 'API/JSContextRefPrivate.h', 'API/JSObjectRef.cpp', 'API/JSObjectRef.h', 'API/JSProfilerPrivate.cpp', @@ -64,6 +64,7 @@ 'bytecode/StructureStubInfo.h', 'bytecompiler/BytecodeGenerator.cpp', 'bytecompiler/BytecodeGenerator.h', + 'bytecompiler/NodesCodegen.cpp', 'bytecompiler/Label.h', 'bytecompiler/LabelScope.h', 'bytecompiler/RegisterID.h', @@ -194,6 +195,7 @@ 'runtime/DateConversion.h', 'runtime/DateInstance.cpp', 'runtime/DateInstance.h', + 'runtime/DateInstanceCache.h', 'runtime/DatePrototype.cpp', 'runtime/DatePrototype.h', 'runtime/Error.cpp', @@ -255,6 +257,7 @@ 'runtime/JSString.cpp', 'runtime/JSString.h', 'runtime/JSType.h', + 'runtime/JSTypeInfo.h', 'runtime/JSValue.cpp', 'runtime/JSValue.h', 'runtime/JSVariableObject.cpp', @@ -287,6 +290,8 @@ 'runtime/ObjectPrototype.h', 'runtime/Operations.cpp', 'runtime/Operations.h', + 'runtime/PropertyDescriptor.cpp', + 'runtime/PropertyDescriptor.h', 'runtime/PropertyMapHashTable.h', 'runtime/PropertyNameArray.cpp', 'runtime/PropertyNameArray.h', @@ -326,9 +331,9 @@ 'runtime/TimeoutChecker.cpp', 'runtime/TimeoutChecker.h', 'runtime/Tracing.h', - 'runtime/TypeInfo.h', 'runtime/UString.cpp', 'runtime/UString.h', + 'runtime/WeakRandom.h', 'wrec/CharacterClass.cpp', 'wrec/CharacterClass.h', 'wrec/CharacterClassConstructor.cpp', @@ -366,8 +371,8 @@ 'wtf/FastMalloc.h', 'wtf/Forward.h', 'wtf/GetPtr.h', - 'wtf/GOwnPtr.cpp', - 'wtf/GOwnPtr.h', + 'wtf/gtk/GOwnPtr.cpp', + 'wtf/gtk/GOwnPtr.h', 'wtf/gtk/MainThreadGtk.cpp', 'wtf/gtk/ThreadingGtk.cpp', 'wtf/HashCountedSet.h', diff --git a/JavaScriptCore/JavaScriptCore.order b/JavaScriptCore/JavaScriptCore.order index 3ae3ec6..d6f6caa 100644 --- a/JavaScriptCore/JavaScriptCore.order +++ b/JavaScriptCore/JavaScriptCore.order @@ -1625,7 +1625,6 @@ __ZN3JSC18EmptyStatementNode12emitBytecodeERNS_17BytecodeGeneratorEPNS_10Registe __ZN3JSCL27compareByStringPairForQSortEPKvS1_ __Z22jsc_pcre_ucp_othercasej __ZN3JSCL35objectProtoFuncPropertyIsEnumerableEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE -__ZNK3JSC8JSObject21getPropertyAttributesEPNS_9ExecStateERKNS_10IdentifierERj __ZN3WTF7HashMapIjN3JSC7JSValueENS_7IntHashIjEENS_10HashTraitsIjEENS5_IS2_EEE3setERKjRKS2_ __ZN3WTF9HashTableIjSt4pairIjN3JSC7JSValueEENS_18PairFirstExtractorIS4_EENS_7IntHashIjEENS_14PairHashTraitsINS_10HashTraitsIjEE __ZN3JSC12RegisterFile21releaseExcessCapacityEv @@ -1841,7 +1840,6 @@ __ZN3JSC6JSCell14toThisJSStringEPNS_9ExecStateE __ZNK3JSC6JSCell12toThisStringEPNS_9ExecStateE __ZN3JSCL27objectProtoFuncLookupSetterEPNS_9ExecStateEPNS_8JSObjectENS_7JSValueERKNS_7ArgListE __ZN3JSC8JSObject12lookupSetterEPNS_9ExecStateERKNS_10IdentifierE -__ZNK3JSC16JSVariableObject21getPropertyAttributesEPNS_9ExecStateERKNS_10IdentifierERj __ZN3JSC9ExecState22regExpConstructorTableEPS0_ __ZN3JSCL24regExpConstructorDollar7EPNS_9ExecStateERKNS_10IdentifierERKNS_12PropertySlotE __ZN3JSCL24regExpConstructorDollar8EPNS_9ExecStateERKNS_10IdentifierERKNS_12PropertySlotE diff --git a/JavaScriptCore/JavaScriptCore.pri b/JavaScriptCore/JavaScriptCore.pri index dd48c9a..aecf01c 100644 --- a/JavaScriptCore/JavaScriptCore.pri +++ b/JavaScriptCore/JavaScriptCore.pri @@ -9,6 +9,11 @@ CONFIG(debug, debug|release) { OBJECTS_DIR = obj/release } +symbian: { + # Need to guarantee this comes before system includes of /epoc32/include + MMP_RULES += "USERINCLUDE ../JavaScriptCore/profiler" +} + INCLUDEPATH = \ $$PWD \ $$PWD/.. \ @@ -36,6 +41,16 @@ GENERATED_SOURCES_DIR_SLASH = $${GENERATED_SOURCES_DIR}$${QMAKE_DIR_SEP} win32-* { LIBS += -lwinmm } +contains(JAVASCRIPTCORE_JIT,yes) { + DEFINES+=ENABLE_JIT=1 + DEFINES+=ENABLE_YARR_JIT=1 + DEFINES+=ENABLE_YARR=1 +} +contains(JAVASCRIPTCORE_JIT,no) { + DEFINES+=ENABLE_JIT=0 + DEFINES+=ENABLE_YARR_JIT=0 + DEFINES+=ENABLE_YARR=0 +} # In debug mode JIT disabled until crash fixed win32-* { @@ -44,23 +59,29 @@ win32-* { # Rules when JIT enabled (not disabled) !contains(DEFINES, ENABLE_JIT=0) { - linux-g++*:greaterThan(QT_GCC_MAJOR_VERSION,3):greaterThan(QT_GCC_MINOR_VERSION,0) { + linux*-g++*:greaterThan(QT_GCC_MAJOR_VERSION,3):greaterThan(QT_GCC_MINOR_VERSION,0) { QMAKE_CXXFLAGS += -fno-stack-protector QMAKE_CFLAGS += -fno-stack-protector } } +wince* { + INCLUDEPATH += $$QT_SOURCE_TREE/src/3rdparty/ce-compat + SOURCES += $$QT_SOURCE_TREE/src/3rdparty/ce-compat/ce_time.c + DEFINES += WINCEBASIC +} + include(pcre/pcre.pri) LUT_FILES += \ + runtime/ArrayPrototype.cpp \ runtime/DatePrototype.cpp \ runtime/JSONObject.cpp \ - runtime/NumberConstructor.cpp \ - runtime/StringPrototype.cpp \ - runtime/ArrayPrototype.cpp \ runtime/MathObject.cpp \ + runtime/NumberConstructor.cpp \ runtime/RegExpConstructor.cpp \ - runtime/RegExpObject.cpp + runtime/RegExpObject.cpp \ + runtime/StringPrototype.cpp KEYWORDLUT_FILES += \ parser/Keywords.table @@ -69,16 +90,6 @@ JSCBISON += \ parser/Grammar.y SOURCES += \ - wtf/Assertions.cpp \ - wtf/ByteArray.cpp \ - wtf/HashTable.cpp \ - wtf/MainThread.cpp \ - wtf/RandomNumber.cpp \ - wtf/RefCountedLeakCounter.cpp \ - wtf/TypeTraits.cpp \ - wtf/unicode/CollatorDefault.cpp \ - wtf/unicode/icu/CollatorICU.cpp \ - wtf/unicode/UTF8.cpp \ API/JSBase.cpp \ API/JSCallbackConstructor.cpp \ API/JSCallbackFunction.cpp \ @@ -89,46 +100,38 @@ SOURCES += \ API/JSStringRef.cpp \ API/JSValueRef.cpp \ API/OpaqueJSString.cpp \ - runtime/InitializeThreading.cpp \ - runtime/JSGlobalData.cpp \ - runtime/JSGlobalObject.cpp \ - runtime/JSStaticScopeObject.cpp \ - runtime/JSVariableObject.cpp \ - runtime/JSActivation.cpp \ - runtime/JSNotAnObject.cpp \ - runtime/JSONObject.cpp \ - runtime/LiteralParser.cpp \ - runtime/MarkStack.cpp \ - runtime/MarkStackPosix.cpp \ - runtime/TimeoutChecker.cpp \ + assembler/ARMAssembler.cpp \ + assembler/MacroAssemblerARM.cpp \ bytecode/CodeBlock.cpp \ - bytecode/StructureStubInfo.cpp \ bytecode/JumpTable.cpp \ - assembler/ARMAssembler.cpp \ - jit/JIT.cpp \ - jit/JITCall.cpp \ + bytecode/Opcode.cpp \ + bytecode/SamplingTool.cpp \ + bytecode/StructureStubInfo.cpp \ + bytecompiler/BytecodeGenerator.cpp \ + bytecompiler/NodesCodegen.cpp \ + debugger/DebuggerActivation.cpp \ + debugger/DebuggerCallFrame.cpp \ + debugger/Debugger.cpp \ + interpreter/CallFrame.cpp \ + interpreter/Interpreter.cpp \ + interpreter/RegisterFile.cpp \ + jit/ExecutableAllocator.cpp \ jit/JITArithmetic.cpp \ + jit/JITCall.cpp \ + jit/JIT.cpp \ jit/JITOpcodes.cpp \ jit/JITPropertyAccess.cpp \ - jit/ExecutableAllocator.cpp \ jit/JITStubs.cpp \ - bytecompiler/BytecodeGenerator.cpp \ - runtime/ExceptionHelpers.cpp \ - runtime/JSPropertyNameIterator.cpp \ - interpreter/Interpreter.cpp \ - bytecode/Opcode.cpp \ - bytecode/SamplingTool.cpp \ - yarr/RegexCompiler.cpp \ - yarr/RegexInterpreter.cpp \ - yarr/RegexJIT.cpp \ - interpreter/RegisterFile.cpp - -win32-*: SOURCES += jit/ExecutableAllocatorWin.cpp -else: SOURCES += jit/ExecutableAllocatorPosix.cpp - -# AllInOneFile.cpp helps gcc analize and optimize code -# Other compilers may be able to do this at link time -SOURCES += \ + parser/Lexer.cpp \ + parser/Nodes.cpp \ + parser/ParserArena.cpp \ + parser/Parser.cpp \ + profiler/HeavyProfile.cpp \ + profiler/Profile.cpp \ + profiler/ProfileGenerator.cpp \ + profiler/ProfileNode.cpp \ + profiler/Profiler.cpp \ + profiler/TreeProfile.cpp \ runtime/ArgList.cpp \ runtime/Arguments.cpp \ runtime/ArrayConstructor.cpp \ @@ -139,60 +142,64 @@ SOURCES += \ runtime/CallData.cpp \ runtime/Collector.cpp \ runtime/CommonIdentifiers.cpp \ + runtime/Completion.cpp \ runtime/ConstructData.cpp \ - wtf/CurrentTime.cpp \ runtime/DateConstructor.cpp \ runtime/DateConversion.cpp \ runtime/DateInstance.cpp \ runtime/DatePrototype.cpp \ - debugger/Debugger.cpp \ - debugger/DebuggerCallFrame.cpp \ - debugger/DebuggerActivation.cpp \ - wtf/dtoa.cpp \ - runtime/Error.cpp \ runtime/ErrorConstructor.cpp \ + runtime/Error.cpp \ runtime/ErrorInstance.cpp \ runtime/ErrorPrototype.cpp \ - interpreter/CallFrame.cpp \ + runtime/ExceptionHelpers.cpp \ + runtime/Executable.cpp \ runtime/FunctionConstructor.cpp \ runtime/FunctionPrototype.cpp \ runtime/GetterSetter.cpp \ runtime/GlobalEvalFunction.cpp \ runtime/Identifier.cpp \ + runtime/InitializeThreading.cpp \ runtime/InternalFunction.cpp \ - runtime/Completion.cpp \ - runtime/JSArray.cpp \ + runtime/JSActivation.cpp \ runtime/JSAPIValueWrapper.cpp \ + runtime/JSArray.cpp \ runtime/JSByteArray.cpp \ runtime/JSCell.cpp \ runtime/JSFunction.cpp \ + runtime/JSGlobalData.cpp \ + runtime/JSGlobalObject.cpp \ runtime/JSGlobalObjectFunctions.cpp \ runtime/JSImmediate.cpp \ runtime/JSLock.cpp \ + runtime/JSNotAnObject.cpp \ runtime/JSNumberCell.cpp \ runtime/JSObject.cpp \ + runtime/JSONObject.cpp \ + runtime/JSPropertyNameIterator.cpp \ + runtime/JSStaticScopeObject.cpp \ runtime/JSString.cpp \ runtime/JSValue.cpp \ + runtime/JSVariableObject.cpp \ runtime/JSWrapperObject.cpp \ - parser/Lexer.cpp \ + runtime/LiteralParser.cpp \ runtime/Lookup.cpp \ + runtime/MarkStack.cpp \ runtime/MathObject.cpp \ runtime/NativeErrorConstructor.cpp \ runtime/NativeErrorPrototype.cpp \ - parser/Nodes.cpp \ runtime/NumberConstructor.cpp \ runtime/NumberObject.cpp \ runtime/NumberPrototype.cpp \ runtime/ObjectConstructor.cpp \ runtime/ObjectPrototype.cpp \ runtime/Operations.cpp \ - parser/Parser.cpp \ - parser/ParserArena.cpp \ + runtime/PropertyDescriptor.cpp \ runtime/PropertyNameArray.cpp \ runtime/PropertySlot.cpp \ runtime/PrototypeFunction.cpp \ - runtime/RegExp.cpp \ runtime/RegExpConstructor.cpp \ + runtime/RegExp.cpp \ runtime/RegExpObject.cpp \ runtime/RegExpPrototype.cpp \ runtime/ScopeChain.cpp \ @@ -200,19 +207,46 @@ SOURCES += \ runtime/StringConstructor.cpp \ runtime/StringObject.cpp \ runtime/StringPrototype.cpp \ - runtime/Structure.cpp \ runtime/StructureChain.cpp \ + runtime/Structure.cpp \ + runtime/TimeoutChecker.cpp \ runtime/UString.cpp \ - profiler/HeavyProfile.cpp \ - profiler/Profile.cpp \ - profiler/ProfileGenerator.cpp \ - profiler/ProfileNode.cpp \ - profiler/Profiler.cpp \ - profiler/TreeProfile.cpp \ + wtf/Assertions.cpp \ + wtf/ByteArray.cpp \ + wtf/CurrentTime.cpp \ wtf/DateMath.cpp \ + wtf/dtoa.cpp \ wtf/FastMalloc.cpp \ + wtf/HashTable.cpp \ + wtf/MainThread.cpp \ + wtf/qt/MainThreadQt.cpp \ + wtf/RandomNumber.cpp \ + wtf/RefCountedLeakCounter.cpp \ wtf/Threading.cpp \ - wtf/qt/MainThreadQt.cpp + wtf/TypeTraits.cpp \ + wtf/unicode/CollatorDefault.cpp \ + wtf/unicode/icu/CollatorICU.cpp \ + wtf/unicode/UTF8.cpp \ + yarr/RegexCompiler.cpp \ + yarr/RegexInterpreter.cpp \ + yarr/RegexJIT.cpp + +symbian { + SOURCES += jit/ExecutableAllocatorSymbian.cpp \ + runtime/MarkStackSymbian.cpp +} else { + win32-*|wince* { + SOURCES += jit/ExecutableAllocatorWin.cpp \ + runtime/MarkStackWin.cpp + } else { + SOURCES += jit/ExecutableAllocatorPosix.cpp \ + runtime/MarkStackPosix.cpp + } +} + +!contains(DEFINES, USE_SYSTEM_MALLOC) { + SOURCES += wtf/TCSystemAlloc.cpp +} !contains(DEFINES, ENABLE_SINGLE_THREADED=1) { SOURCES += wtf/qt/ThreadingQt.cpp diff --git a/JavaScriptCore/JavaScriptCore.pro b/JavaScriptCore/JavaScriptCore.pro index 0cd2e1a..0d6becb 100644 --- a/JavaScriptCore/JavaScriptCore.pro +++ b/JavaScriptCore/JavaScriptCore.pro @@ -16,7 +16,6 @@ CONFIG(QTDIR_build) { include($$QT_SOURCE_TREE/src/qbase.pri) INSTALLS = DESTDIR = $$OLDDESTDIR - PRECOMPILED_HEADER = $$PWD/../WebKit/qt/WebKit_pch.h DEFINES *= NDEBUG } @@ -53,17 +52,11 @@ win32-g++ { QMAKE_LIBDIR_POST += $$split(TMPPATH,";") } -DEFINES += WTF_USE_JAVASCRIPTCORE_BINDINGS=1 - DEFINES += WTF_CHANGES=1 include(JavaScriptCore.pri) QMAKE_EXTRA_TARGETS += generated_files -lessThan(QT_MINOR_VERSION, 4) { - DEFINES += QT_BEGIN_NAMESPACE="" QT_END_NAMESPACE="" -} - *-g++*:QMAKE_CXXFLAGS_RELEASE -= -O2 *-g++*:QMAKE_CXXFLAGS_RELEASE += -O3 diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.make b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.make index fbbe23e..806894a 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.make +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.make @@ -1,7 +1,7 @@ !IF !defined(BUILDSTYLE) BUILDSTYLE=Release !ELSEIF "$(BUILDSTYLE)"=="DEBUG" -BUILDSTYLE=Debug_Internal +BUILDSTYLE=Debug_All !ENDIF install: diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.sln b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.sln index 32e7301..69c21bc 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.sln +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore.sln @@ -20,6 +20,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "JavaScriptCoreGenerated", " EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug_All|Win32 = Debug_All|Win32
Debug_Internal|Win32 = Debug_Internal|Win32
Debug|Win32 = Debug|Win32
Release_PGOInstrument|Win32 = Release_PGOInstrument|Win32
@@ -27,6 +28,8 @@ Global Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug_All|Win32.Build.0 = Debug_All|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug_Internal|Win32.ActiveCfg = Debug_Internal|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug_Internal|Win32.Build.0 = Debug_Internal|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug|Win32.ActiveCfg = Debug|Win32
@@ -37,6 +40,8 @@ Global {011D10F1-B656-4A1B-A0C3-3842F02122C5}.Release_PGOOptimize|Win32.Build.0 = Release_PGOOptimize|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Release|Win32.ActiveCfg = Release|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Release|Win32.Build.0 = Release|Win32
+ {C59E5129-B453-49B7-A52B-1E104715F76E}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {C59E5129-B453-49B7-A52B-1E104715F76E}.Debug_All|Win32.Build.0 = Debug_All|Win32
{C59E5129-B453-49B7-A52B-1E104715F76E}.Debug_Internal|Win32.ActiveCfg = Debug_Internal|Win32
{C59E5129-B453-49B7-A52B-1E104715F76E}.Debug_Internal|Win32.Build.0 = Debug_Internal|Win32
{C59E5129-B453-49B7-A52B-1E104715F76E}.Debug|Win32.ActiveCfg = Debug|Win32
@@ -47,6 +52,8 @@ Global {C59E5129-B453-49B7-A52B-1E104715F76E}.Release_PGOOptimize|Win32.Build.0 = Release|Win32
{C59E5129-B453-49B7-A52B-1E104715F76E}.Release|Win32.ActiveCfg = Release|Win32
{C59E5129-B453-49B7-A52B-1E104715F76E}.Release|Win32.Build.0 = Release|Win32
+ {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug_All|Win32.Build.0 = Debug_All|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug_Internal|Win32.ActiveCfg = Debug_Internal|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug_Internal|Win32.Build.0 = Debug_Internal|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug|Win32.ActiveCfg = Debug|Win32
@@ -57,26 +64,30 @@ Global {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release_PGOOptimize|Win32.Build.0 = Release|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release|Win32.ActiveCfg = Release|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release|Win32.Build.0 = Release|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_Internal|Win32.ActiveCfg = Debug|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_Internal|Win32.Build.0 = Debug|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug|Win32.ActiveCfg = Debug|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug|Win32.Build.0 = Debug|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_PGOInstrument|Win32.ActiveCfg = Release|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_PGOInstrument|Win32.Build.0 = Release|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_PGOOptimize|Win32.ActiveCfg = Release|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_PGOOptimize|Win32.Build.0 = Release|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Release|Win32.ActiveCfg = Release|Win32
- {DA31DA52-6675-48D4-89E0-333A7144397C}.Release|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_Internal|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_Internal|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOInstrument|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOInstrument|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOOptimize|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOOptimize|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release|Win32.Build.0 = Release|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_All|Win32.ActiveCfg = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_All|Win32.Build.0 = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_Internal|Win32.ActiveCfg = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug_Internal|Win32.Build.0 = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug|Win32.ActiveCfg = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Debug|Win32.Build.0 = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_PGOInstrument|Win32.ActiveCfg = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_PGOInstrument|Win32.Build.0 = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_PGOOptimize|Win32.ActiveCfg = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release_PGOOptimize|Win32.Build.0 = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release|Win32.ActiveCfg = all|Win32
+ {DA31DA52-6675-48D4-89E0-333A7144397C}.Release|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_All|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_All|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_Internal|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_Internal|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOInstrument|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOInstrument|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOOptimize|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOOptimize|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release|Win32.Build.0 = all|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def index 0de51bf..aae8118 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.def @@ -1,22 +1,18 @@ -LIBRARY "JavaScriptCore" - EXPORTS - ?from@UString@JSC@@SA?AV12@N@Z - ?nonInlineNaN@JSC@@YANXZ - ?synthesizePrototype@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z - ?toObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z - ?toThisObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z + ??0Collator@WTF@@QAE@PBD@Z - ??0Debugger@JSC@@QAE@XZ + ??0DateInstance@JSC@@QAE@PAVExecState@1@N@Z ??0DropAllLocks@JSLock@JSC@@QAE@W4JSLockBehavior@2@@Z - ??0InternalFunction@JSC@@IAE@PAVJSGlobalData@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@ABVIdentifier@1@@Z - ??0JSByteArray@JSC@@QAE@PAVExecState@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@PAVByteArray@4@PBUClassInfo@1@@Z - ??0JSFunction@JSC@@QAE@PAVExecState@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V61@ABVArgList@1@@Z@Z + ??0InternalFunction@JSC@@IAE@PAVJSGlobalData@1@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@ABVIdentifier@1@@Z + ??0JSArray@JSC@@QAE@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@@Z + ??0JSArray@JSC@@QAE@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@ABVArgList@1@@Z + ??0JSByteArray@JSC@@QAE@PAVExecState@1@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@PAVByteArray@4@PBUClassInfo@1@@Z + ??0JSFunction@JSC@@QAE@PAVExecState@1@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V61@ABVArgList@1@@Z@Z ??0Mutex@WTF@@QAE@XZ ??0PrototypeFunction@JSC@@QAE@PAVExecState@1@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V41@ABVArgList@1@@Z@Z - ??0PrototypeFunction@JSC@@QAE@PAVExecState@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V61@ABVArgList@1@@Z@Z + ??0PrototypeFunction@JSC@@QAE@PAVExecState@1@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V61@ABVArgList@1@@Z@Z ??0RefCountedLeakCounter@WTF@@QAE@PBD@Z - ??0StringObject@JSC@@QAE@PAVExecState@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@ABVUString@1@@Z + ??0StringObject@JSC@@QAE@PAVExecState@1@V?$NonNullPassRefPtr@VStructure@JSC@@@WTF@@ABVUString@1@@Z ??0Structure@JSC@@AAE@VJSValue@1@ABVTypeInfo@1@@Z ??0ThreadCondition@WTF@@QAE@XZ ??0UString@JSC@@QAE@PBD@Z @@ -30,12 +26,14 @@ EXPORTS ??1JSGlobalObject@JSC@@UAE@XZ ??1Mutex@WTF@@QAE@XZ ??1RefCountedLeakCounter@WTF@@QAE@XZ + ??1Rope@JSString@JSC@@QAE@XZ ??1Structure@JSC@@QAE@XZ ??1ThreadCondition@WTF@@QAE@XZ ??2JSCell@JSC@@SAPAXIPAVExecState@1@@Z ??2JSGlobalObject@JSC@@SAPAXIPAVJSGlobalData@1@@Z ??4UString@JSC@@QAEAAV01@PBD@Z ??8JSC@@YA_NABVUString@0@0@Z + ?NaN@JSC@@3NB ?UTF8String@UString@JSC@@QBE?AVCString@2@_N@Z ?add@Identifier@JSC@@SA?AV?$PassRefPtr@URep@UString@JSC@@@WTF@@PAVExecState@2@PBD@Z ?add@PropertyNameArray@JSC@@QAEXPAURep@UString@2@@Z @@ -47,7 +45,6 @@ EXPORTS ?allocate@Heap@JSC@@QAEPAXI@Z ?allocatePropertyStorage@JSObject@JSC@@QAEXII@Z ?allocateStack@MarkStack@JSC@@CAPAXI@Z - ?allocateStack@MarkStack@JSC@@CAPAXI@Z ?append@UString@JSC@@QAEAAV12@ABV12@@Z ?append@UString@JSC@@QAEAAV12@PBD@Z ?ascii@UString@JSC@@QBEPADXZ @@ -56,6 +53,7 @@ EXPORTS ?calculatedFunctionName@DebuggerCallFrame@JSC@@QBE?AVUString@2@XZ ?call@JSC@@YA?AVJSValue@1@PAVExecState@1@V21@W4CallType@1@ABTCallData@1@1ABVArgList@1@@Z ?callOnMainThread@WTF@@YAXP6AXPAX@Z0@Z + ?callOnMainThreadAndWait@WTF@@YAXP6AXPAX@Z0@Z ?changePrototypeTransition@Structure@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@PAV12@VJSValue@2@@Z ?checkSameIdentifierTable@Identifier@JSC@@CAXPAVExecState@2@PAURep@UString@2@@Z ?checkSameIdentifierTable@Identifier@JSC@@CAXPAVJSGlobalData@2@PAURep@UString@2@@Z @@ -67,34 +65,40 @@ EXPORTS ?collect@Heap@JSC@@QAE_NXZ ?computeHash@Rep@UString@JSC@@SAIPBDH@Z ?computeHash@Rep@UString@JSC@@SAIPB_WH@Z + ?configurable@PropertyDescriptor@JSC@@QBE_NXZ ?construct@JSC@@YAPAVJSObject@1@PAVExecState@1@VJSValue@1@W4ConstructType@1@ABTConstructData@1@ABVArgList@1@@Z ?constructArray@JSC@@YAPAVJSArray@1@PAVExecState@1@ABVArgList@1@@Z ?constructEmptyArray@JSC@@YAPAVJSArray@1@PAVExecState@1@@Z ?constructEmptyObject@JSC@@YAPAVJSObject@1@PAVExecState@1@@Z ?constructFunction@JSC@@YAPAVJSObject@1@PAVExecState@1@ABVArgList@1@ABVIdentifier@1@ABVUString@1@H@Z ?convertUTF16ToUTF8@Unicode@WTF@@YA?AW4ConversionResult@12@PAPB_WPB_WPAPADPAD_N@Z - ?copyParameters@FunctionBodyNode@JSC@@QAEPAVIdentifier@2@XZ ?create@ByteArray@WTF@@SA?AV?$PassRefPtr@VByteArray@WTF@@@2@I@Z - ?create@FunctionBodyNode@JSC@@SA?AV?$PassRefPtr@VFunctionBodyNode@JSC@@@WTF@@PAVJSGlobalData@2@PAVSourceElements@2@PAV?$Vector@U?$pair@VIdentifier@JSC@@I@std@@$0A@@4@PAV?$Vector@PAVFuncDeclNode@JSC@@$0A@@4@ABVSourceCode@2@IH@Z ?create@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@_N@Z ?create@OpaqueJSString@@SA?AV?$PassRefPtr@UOpaqueJSString@@@WTF@@ABVUString@JSC@@@Z ?create@Rep@UString@JSC@@SA?AV?$PassRefPtr@URep@UString@JSC@@@WTF@@PA_WHV?$PassRefPtr@V?$CrossThreadRefCounted@V?$OwnFastMallocPtr@_W@WTF@@@WTF@@@5@@Z ?createEmptyString@SmallStrings@JSC@@AAEXPAVJSGlobalData@2@@Z ?createInheritorID@JSObject@JSC@@AAEPAVStructure@2@XZ + ?createInterruptedExecutionException@JSC@@YA?AVJSValue@1@PAVJSGlobalData@1@@Z ?createLeaked@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@XZ + ?createSingleCharacterString@SmallStrings@JSC@@AAEXPAVJSGlobalData@2@E@Z + ?createStackOverflowError@JSC@@YA?AVJSValue@1@PAVExecState@1@@Z ?createStructure@JSByteArray@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@VJSValue@2@@Z ?createTable@HashTable@JSC@@ABEXPAVJSGlobalData@2@@Z ?createThread@WTF@@YAIP6APAXPAX@Z0@Z ?createThread@WTF@@YAIP6APAXPAX@Z0PBD@Z + ?createTypeError@JSC@@YA?AVJSValue@1@PAVExecState@1@PBD@Z ?currentThread@WTF@@YAIXZ ?currentTime@WTF@@YANXZ ?decrement@RefCountedLeakCounter@WTF@@QAEXXZ + ?defaultAttributes@PropertyDescriptor@JSC@@0IA ?defaultValue@JSObject@JSC@@UBE?AVJSValue@2@PAVExecState@2@W4PreferredPrimitiveType@2@@Z - ?defineGetter@JSGlobalObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAVJSObject@2@@Z - ?defineGetter@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAV12@@Z - ?defineSetter@JSGlobalObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAVJSObject@2@@Z - ?defineSetter@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAV12@@Z + ?defineGetter@JSGlobalObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAVJSObject@2@I@Z + ?defineGetter@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAV12@I@Z + ?defineOwnProperty@JSObject@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertyDescriptor@2@_N@Z + ?defineSetter@JSGlobalObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAVJSObject@2@I@Z + ?defineSetter@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAV12@I@Z ?deleteOwnedPtr@WTF@@YAXPAUHBITMAP__@@@Z + ?deleteOwnedPtr@WTF@@YAXPAUHDC__@@@Z ?deleteOwnedPtr@WTF@@YAXPAUHRGN__@@@Z ?deleteProperty@JSCell@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@@Z ?deleteProperty@JSCell@JSC@@UAE_NPAVExecState@2@I@Z @@ -107,8 +111,13 @@ EXPORTS ?despecifyFunctionTransition@Structure@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@PAV12@ABVIdentifier@2@@Z ?destroy@Heap@JSC@@QAEXXZ ?destroy@Rep@UString@JSC@@QAEXXZ + ?destroyJSGlobalObjectData@JSGlobalObject@JSC@@CAXPAX@Z ?detach@Debugger@JSC@@UAEXPAVJSGlobalObject@2@@Z ?detachThread@WTF@@YAXI@Z + ?didTimeOut@TimeoutChecker@JSC@@QAE_NPAVExecState@2@@Z + ?dumpSampleData@JSGlobalData@JSC@@QAEXPAVExecState@2@@Z + ?doubleToStringInJavaScriptFormat@WTF@@YAXNQADPAI@Z + ?enumerable@PropertyDescriptor@JSC@@QBE_NXZ ?equal@Identifier@JSC@@SA_NPBURep@UString@2@PBD@Z ?equal@JSC@@YA_NPBURep@UString@1@0@Z ?evaluate@DebuggerCallFrame@JSC@@QBE?AVJSValue@2@ABVUString@2@AAV32@@Z @@ -120,16 +129,22 @@ EXPORTS ?fastRealloc@WTF@@YAPAXPAXI@Z ?fastZeroedMalloc@WTF@@YAPAXI@Z ?fillGetterPropertySlot@JSObject@JSC@@QAEXAAVPropertySlot@2@PAVJSValue@2@@Z - ?finishParsing@FunctionBodyNode@JSC@@QAEXPAVIdentifier@2@I@Z ?focus@Profile@JSC@@QAEXPBVProfileNode@2@@Z ?from@UString@JSC@@SA?AV12@H@Z ?from@UString@JSC@@SA?AV12@I@Z + ?from@UString@JSC@@SA?AV12@N@Z ?functionName@DebuggerCallFrame@JSC@@QBEPBVUString@2@XZ ?get@Structure@JSC@@QAEIPBURep@UString@2@AAIAAPAVJSCell@2@@Z ?getCallData@JSCell@JSC@@UAE?AW4CallType@2@AATCallData@2@@Z ?getConstructData@JSCell@JSC@@UAE?AW4ConstructType@2@AATConstructData@2@@Z ?getJSNumber@JSCell@JSC@@UAE?AVJSValue@2@XZ ?getObject@JSCell@JSC@@QAEPAVJSObject@2@XZ + ?getOwnPropertyDescriptor@JSObject@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertyDescriptor@2@@Z + ?getOwnPropertyDescriptor@JSString@JSC@@EAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertyDescriptor@2@@Z + ?getOwnPropertyDescriptor@StringObject@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertyDescriptor@2@@Z + ?getOwnPropertyNames@JSObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@@Z + ?getOwnPropertyNames@JSVariableObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@@Z + ?getOwnPropertyNames@StringObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@@Z ?getOwnPropertySlot@JSCell@JSC@@EAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertySlot@2@@Z ?getOwnPropertySlot@JSCell@JSC@@EAE_NPAVExecState@2@IAAVPropertySlot@2@@Z ?getOwnPropertySlot@JSObject@JSC@@UAE_NPAVExecState@2@IAAVPropertySlot@2@@Z @@ -137,23 +152,22 @@ EXPORTS ?getOwnPropertySlot@JSString@JSC@@EAE_NPAVExecState@2@IAAVPropertySlot@2@@Z ?getOwnPropertySlot@StringObject@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertySlot@2@@Z ?getOwnPropertySlot@StringObject@JSC@@UAE_NPAVExecState@2@IAAVPropertySlot@2@@Z - ?getPrimitiveNumber@JSAPIValueWrapper@JSC@@UAE_NPAVExecState@2@AANAAVJSValue@2@@Z + ?getPrimitiveNumber@JSCell@JSC@@UAE_NPAVExecState@2@AANAAVJSValue@2@@Z ?getPrimitiveNumber@JSObject@JSC@@UAE_NPAVExecState@2@AANAAVJSValue@2@@Z ?getPrimitiveNumber@JSString@JSC@@EAE_NPAVExecState@2@AANAAVJSValue@2@@Z - ?getPropertyAttributes@JSObject@JSC@@UBE_NPAVExecState@2@ABVIdentifier@2@AAI@Z - ?getPropertyAttributes@JSVariableObject@JSC@@UBE_NPAVExecState@2@ABVIdentifier@2@AAI@Z + ?getPropertyDescriptor@JSObject@JSC@@QAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertyDescriptor@2@@Z ?getPropertyNames@JSObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@@Z - ?getPropertyNames@JSVariableObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@@Z - ?getPropertyNames@StringObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@@Z ?getSlice@ArgList@JSC@@QBEXHAAV12@@Z - ?getString@JSCell@JSC@@QBE?AVUString@2@XZ - ?getString@JSCell@JSC@@QBE_NAAVUString@2@@Z + ?getString@JSCell@JSC@@QBE?AVUString@2@PAVExecState@2@@Z + ?getString@JSCell@JSC@@QBE_NPAVExecState@2@AAVUString@2@@Z ?getUInt32@JSCell@JSC@@UBE_NAAI@Z + ?getter@PropertyDescriptor@JSC@@QBE?AVJSValue@2@XZ ?globalExec@JSGlobalObject@JSC@@UAEPAVExecState@2@XZ ?globalObjectCount@Heap@JSC@@QAEIXZ ?hasInstance@JSObject@JSC@@UAE_NPAVExecState@2@VJSValue@2@1@Z ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@ABVIdentifier@2@@Z ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@I@Z + ?hasTransition@Structure@JSC@@QAE_NPAURep@UString@2@I@Z ?heap@Heap@JSC@@SAPAV12@VJSValue@2@@Z ?increment@RefCountedLeakCounter@WTF@@QAEXXZ ?init@JSGlobalObject@JSC@@AAEXPAVJSObject@2@@Z @@ -161,10 +175,12 @@ EXPORTS ?initializeThreading@JSC@@YAXXZ ?initializeThreading@WTF@@YAXXZ ?is8Bit@UString@JSC@@QBE_NXZ + ?isAccessorDescriptor@PropertyDescriptor@JSC@@QBE_NXZ ?isBusy@Heap@JSC@@QAE_NXZ + ?isDataDescriptor@PropertyDescriptor@JSC@@QBE_NXZ ?isDynamicScope@JSGlobalObject@JSC@@UBE_NXZ ?isGetterSetter@JSCell@JSC@@UBE_NXZ - ?isHostFunction@FunctionBodyNode@JSC@@QBE_NXZ + ?isHostFunctionNonInline@JSFunction@JSC@@ABE_NXZ ?isMainThread@WTF@@YA_NXZ ?isVariableObject@JSVariableObject@JSC@@UBE_NXZ ?jsNumberCell@JSC@@YA?AVJSValue@1@PAVExecState@1@N@Z @@ -180,9 +196,10 @@ EXPORTS ?lookupSetter@JSObject@JSC@@UAE?AVJSValue@2@PAVExecState@2@ABVIdentifier@2@@Z ?markChildren@JSGlobalObject@JSC@@UAEXAAVMarkStack@2@@Z ?markChildren@JSObject@JSC@@UAEXAAVMarkStack@2@@Z - ?markChildren@JSWrapperObject@JSC@@UAEXAAVMarkStack@2@@Z + ?markChildren@JSWrapperObject@JSC@@EAEXAAVMarkStack@2@@Z ?materializePropertyMap@Structure@JSC@@AAEXXZ - ?name@InternalFunction@JSC@@QAEABVUString@2@PAVJSGlobalData@2@@Z + ?name@InternalFunction@JSC@@QAEABVUString@2@PAVExecState@2@@Z + ?nonInlineNaN@JSC@@YANXZ ?objectCount@Heap@JSC@@QAEIXZ ?objectProtoFuncToString@JSC@@YI?AVJSValue@1@PAVExecState@1@PAVJSObject@1@V21@ABVArgList@1@@Z ?parse@Parser@JSC@@AAEXPAVJSGlobalData@2@PAHPAVUString@2@@Z @@ -206,28 +223,44 @@ EXPORTS ?putWithAttributes@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@VJSValue@2@I_NAAVPutPropertySlot@2@@Z ?putWithAttributes@JSObject@JSC@@UAEXPAVExecState@2@IVJSValue@2@I@Z ?randomNumber@WTF@@YANXZ + ?recompileAllJSFunctions@Debugger@JSC@@QAEXPAVJSGlobalData@2@@Z ?recordExtraCost@Heap@JSC@@AAEXI@Z ?releaseStack@MarkStack@JSC@@CAXPAXI@Z ?reset@ParserArena@JSC@@QAEXXZ ?reset@TimeoutChecker@JSC@@QAEXXZ + ?resetDateCache@JSGlobalData@JSC@@QAEXXZ + ?resolveRope@JSString@JSC@@ABEXPAVExecState@2@@Z ?restoreAll@Profile@JSC@@QAEXXZ ?retrieveCaller@Interpreter@JSC@@QBE?AVJSValue@2@PAVExecState@2@PAVInternalFunction@2@@Z ?retrieveLastCaller@Interpreter@JSC@@QBEXPAVExecState@2@AAH1AAVUString@2@AAVJSValue@2@@Z + ?setAccessorDescriptor@PropertyDescriptor@JSC@@QAEXVJSValue@2@0I@Z + ?setConfigurable@PropertyDescriptor@JSC@@QAEX_N@Z + ?setDescriptor@PropertyDescriptor@JSC@@QAEXVJSValue@2@I@Z ?setDumpsGeneratedCode@BytecodeGenerator@JSC@@SAX_N@Z - ?setGCProtectNeedsLocking@Heap@JSC@@QAEXXZ + ?setEnumerable@PropertyDescriptor@JSC@@QAEX_N@Z + ?setGetter@PropertyDescriptor@JSC@@QAEXVJSValue@2@@Z + ?setLength@JSArray@JSC@@QAEXI@Z ?setLoc@StatementNode@JSC@@QAEXHH@Z ?setMainThreadCallbacksPaused@WTF@@YAX_N@Z ?setOrderLowerFirst@Collator@WTF@@QAEX_N@Z + ?setSetter@PropertyDescriptor@JSC@@QAEXVJSValue@2@@Z + ?setUndefined@PropertyDescriptor@JSC@@QAEXXZ ?setUpStaticFunctionSlot@JSC@@YAXPAVExecState@1@PBVHashEntry@1@PAVJSObject@1@ABVIdentifier@1@AAVPropertySlot@1@@Z + ?setWritable@PropertyDescriptor@JSC@@QAEX_N@Z + ?setter@PropertyDescriptor@JSC@@QBE?AVJSValue@2@XZ ?sharedBuffer@Rep@UString@JSC@@QAEPAV?$CrossThreadRefCounted@V?$OwnFastMallocPtr@_W@WTF@@@WTF@@XZ ?signal@ThreadCondition@WTF@@QAEXXZ ?slowAppend@MarkedArgumentBuffer@JSC@@AAEXVJSValue@2@@Z ?startIgnoringLeaks@Structure@JSC@@SAXXZ ?startProfiling@Profiler@JSC@@QAEXPAVExecState@2@ABVUString@2@@Z + ?startSampling@JSGlobalData@JSC@@QAEXXZ ?stopIgnoringLeaks@Structure@JSC@@SAXXZ ?stopProfiling@Profiler@JSC@@QAE?AV?$PassRefPtr@VProfile@JSC@@@WTF@@PAVExecState@2@ABVUString@2@@Z + ?stopSampling@JSGlobalData@JSC@@QAEXXZ ?strtod@WTF@@YANPBDPAPAD@Z ?substr@UString@JSC@@QBE?AV12@HH@Z + ?symbolTableGet@JSVariableObject@JSC@@IAE_NABVIdentifier@2@AAVPropertyDescriptor@2@@Z + ?synthesizePrototype@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z ?thisObject@DebuggerCallFrame@JSC@@QBEPAVJSObject@2@XZ ?throwError@JSC@@YAPAVJSObject@1@PAVExecState@1@W4ErrorType@1@@Z ?throwError@JSC@@YAPAVJSObject@1@PAVExecState@1@W4ErrorType@1@ABVUString@1@@Z @@ -235,36 +268,36 @@ EXPORTS ?timedWait@ThreadCondition@WTF@@QAE_NAAVMutex@2@N@Z ?tlsKeyCount@WTF@@YAAAJXZ ?tlsKeys@WTF@@YAPAKXZ - ?toBoolean@JSAPIValueWrapper@JSC@@UBE_NPAVExecState@2@@Z + ?toBoolean@JSCell@JSC@@UBE_NPAVExecState@2@@Z ?toBoolean@JSObject@JSC@@UBE_NPAVExecState@2@@Z ?toBoolean@JSString@JSC@@EBE_NPAVExecState@2@@Z ?toInt32SlowCase@JSC@@YAHNAA_N@Z - ?toNumber@JSAPIValueWrapper@JSC@@UBENPAVExecState@2@@Z + ?toNumber@JSCell@JSC@@UBENPAVExecState@2@@Z ?toNumber@JSObject@JSC@@UBENPAVExecState@2@@Z ?toNumber@JSString@JSC@@EBENPAVExecState@2@@Z - ?toObject@JSAPIValueWrapper@JSC@@UBEPAVJSObject@2@PAVExecState@2@@Z + ?toObject@JSCell@JSC@@UBEPAVJSObject@2@PAVExecState@2@@Z ?toObject@JSObject@JSC@@UBEPAV12@PAVExecState@2@@Z ?toObject@JSString@JSC@@EBEPAVJSObject@2@PAVExecState@2@@Z - ?toPrimitive@JSAPIValueWrapper@JSC@@UBE?AVJSValue@2@PAVExecState@2@W4PreferredPrimitiveType@2@@Z + ?toObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z + ?toPrimitive@JSCell@JSC@@UBE?AVJSValue@2@PAVExecState@2@W4PreferredPrimitiveType@2@@Z ?toPrimitive@JSString@JSC@@EBE?AVJSValue@2@PAVExecState@2@W4PreferredPrimitiveType@2@@Z ?toStrictUInt32@UString@JSC@@QBEIPA_N@Z - ?toString@JSAPIValueWrapper@JSC@@UBE?AVUString@2@PAVExecState@2@@Z + ?toString@JSCell@JSC@@UBE?AVUString@2@PAVExecState@2@@Z ?toString@JSObject@JSC@@UBE?AVUString@2@PAVExecState@2@@Z ?toString@JSString@JSC@@EBE?AVUString@2@PAVExecState@2@@Z - ?toString@StringObject@JSC@@EBE?AVUString@2@PAVExecState@2@@Z ?toThisJSString@JSCell@JSC@@UAEPAVJSString@2@PAVExecState@2@@Z ?toThisJSString@JSString@JSC@@EAEPAV12@PAVExecState@2@@Z - ?toThisJSString@StringObject@JSC@@EAEPAVJSString@2@PAVExecState@2@@Z ?toThisObject@JSCell@JSC@@UBEPAVJSObject@2@PAVExecState@2@@Z ?toThisObject@JSObject@JSC@@UBEPAV12@PAVExecState@2@@Z ?toThisObject@JSString@JSC@@EBEPAVJSObject@2@PAVExecState@2@@Z + ?toThisObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z ?toThisString@JSCell@JSC@@UBE?AVUString@2@PAVExecState@2@@Z ?toThisString@JSString@JSC@@EBE?AVUString@2@PAVExecState@2@@Z - ?toThisString@StringObject@JSC@@EBE?AVUString@2@PAVExecState@2@@Z ?toUInt32@UString@JSC@@QBEIPA_N@Z ?toUInt32@UString@JSC@@QBEIPA_N_N@Z ?toUInt32SlowCase@JSC@@YAINAA_N@Z - ?tryFastCalloc@WTF@@YAPAXII@Z + ?tryFastCalloc@WTF@@YA?AUTryMallocReturnValue@1@II@Z + ?tryFastMalloc@WTF@@YA?AUTryMallocReturnValue@1@I@Z ?tryLock@Mutex@WTF@@QAE_NXZ ?type@DebuggerCallFrame@JSC@@QBE?AW4Type@12@XZ ?unlock@JSLock@JSC@@SAXW4JSLockBehavior@2@@Z @@ -274,6 +307,7 @@ EXPORTS ?unwrappedObject@JSObject@JSC@@UAEPAV12@XZ ?wait@ThreadCondition@WTF@@QAEXAAVMutex@2@@Z ?waitForThreadCompletion@WTF@@YAHIPAPAX@Z + ?writable@PropertyDescriptor@JSC@@QBE_NXZ WTFLog WTFLogVerbose WTFReportArgumentAssertionFailure diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.rc b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.rc index bb2b0fe..ba59bb8 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.rc +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.rc @@ -1,7 +1,7 @@ // Microsoft Visual C++ generated resource script. // #include "autoversion.h" -#include "winres.h" +#include "winresrc.h" #ifdef _WIN32 LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US @@ -14,8 +14,8 @@ LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US // VS_VERSION_INFO VERSIONINFO - FILEVERSION __VERSION_MAJOR__,__BUILD_NUMBER_MAJOR__,__BUILD_NUMBER_MINOR__,__BUILD_NUMBER_VARIANT__ - PRODUCTVERSION __VERSION_MAJOR__,__VERSION_MINOR__,__VERSION_TINY__,0 + FILEVERSION __VERSION_MAJOR__,__VERSION_MINOR__,__VERSION_TINY__,__VERSION_BUILD__ + PRODUCTVERSION __VERSION_MAJOR__,__VERSION_MINOR__,__VERSION_TINY__,__VERSION_BUILD__ FILEFLAGSMASK 0x17L #ifdef _DEBUG FILEFLAGS 0x1L @@ -37,7 +37,7 @@ BEGIN VALUE "LegalCopyright", "Copyright Apple Inc. 2003-2009" VALUE "OriginalFilename", "JavaScriptCore.dll" VALUE "ProductName", " JavaScriptCore" - VALUE "ProductVersion", __BUILD_NUMBER_SHORT__ + VALUE "ProductVersion", __VERSION_TEXT__ END END BLOCK "VarFileInfo" diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj index 1c5e963..5b7f9ad 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore.vcproj @@ -328,7 +328,7 @@ <Configuration
Name="Debug_CFLite|Win32"
ConfigurationType="2"
- InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\debug.vsprops;$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;.\JavaScriptCoreCommon.vsprops;.\JavaScriptCoreCFLite.vsprops"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\debug_wincairo.vsprops;$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;.\JavaScriptCoreCommon.vsprops;.\JavaScriptCoreCFLite.vsprops"
CharacterSet="1"
>
<Tool
@@ -448,6 +448,67 @@ Name="VCPostBuildEventTool"
/>
</Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="2"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_internal.vsprops;.\JavaScriptCoreCommon.vsprops;.\JavaScriptCoreCF.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_all.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
</Configurations>
<References>
</References>
@@ -604,6 +665,18 @@ >
</File>
<File
+ RelativePath="..\..\runtime\DateInstanceCache.h"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wtf\DateMath.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\wtf\DateMath.h"
+ >
+ </File>
+ <File
RelativePath="..\..\runtime\DatePrototype.cpp"
>
</File>
@@ -644,6 +717,10 @@ >
</File>
<File
+ RelativePath="..\..\runtime\Executable.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\runtime\FunctionConstructor.cpp"
>
</File>
@@ -884,11 +961,11 @@ >
</File>
<File
- RelativePath="..\..\runtime\MarkStack.h"
+ RelativePath="..\..\runtime\MarkStack.cpp"
>
</File>
<File
- RelativePath="..\..\runtime\MarkStack.cpp"
+ RelativePath="..\..\runtime\MarkStack.h"
>
</File>
<File
@@ -948,6 +1025,10 @@ >
</File>
<File
+ RelativePath="..\..\runtime\NumericStrings.h"
+ >
+ </File>
+ <File
RelativePath="..\..\runtime\ObjectConstructor.cpp"
>
</File>
@@ -972,6 +1053,14 @@ >
</File>
<File
+ RelativePath="..\..\runtime\PropertyDescriptor.cpp"
+ >
+ </File>
+ <File
+ RelativePath="..\..\runtime\PropertyDescriptor.h"
+ >
+ </File>
+ <File
RelativePath="..\..\runtime\PropertyMapHashTable.h"
>
</File>
@@ -1123,6 +1212,10 @@ RelativePath="..\..\runtime\UString.h"
>
</File>
+ <File
+ RelativePath="..\..\runtime\WeakRandom.h"
+ >
+ </File>
<Filter
Name="DerivedSources"
>
@@ -1193,6 +1286,14 @@ DisableSpecificWarnings="4701"
/>
</FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ DisableSpecificWarnings="4701"
+ />
+ </FileConfiguration>
</File>
<File
RelativePath="$(WebKitOutputDir)\obj\$(ProjectName)\DerivedSources\Grammar.h"
@@ -1324,6 +1425,10 @@ >
</File>
<File
+ RelativePath="..\..\API\JSContextRefPrivate.h"
+ >
+ </File>
+ <File
RelativePath="..\..\API\JSObjectRef.cpp"
>
</File>
@@ -1444,6 +1549,10 @@ >
</File>
<File
+ RelativePath="..\..\bytecompiler\NodesCodegen.cpp"
+ >
+ </File>
+ <File
RelativePath="..\..\bytecompiler\Label.h"
>
</File>
@@ -1632,15 +1741,11 @@ >
</File>
<File
- RelativePath="..\..\assembler\LinkBuffer.h"
- >
- </File>
- <File
- RelativePath="..\..\assembler\RepatchBuffer.h"
+ RelativePath="..\..\assembler\AssemblerBuffer.h"
>
</File>
<File
- RelativePath="..\..\assembler\AssemblerBuffer.h"
+ RelativePath="..\..\assembler\LinkBuffer.h"
>
</File>
<File
@@ -1656,6 +1761,10 @@ >
</File>
<File
+ RelativePath="..\..\assembler\RepatchBuffer.h"
+ >
+ </File>
+ <File
RelativePath="..\..\assembler\X86Assembler.h"
>
</File>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCFLite.vsprops b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCFLite.vsprops index 02f213b..8c9e31f 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCFLite.vsprops +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCFLite.vsprops @@ -6,6 +6,6 @@ >
<Tool
Name="VCLinkerTool"
- AdditionalDependencies="CFLite$(LibraryConfigSuffix).lib"
+ AdditionalDependencies="CFLite$(WebKitConfigSuffix).lib"
/>
</VisualStudioPropertySheet>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops index 5f90011..682e01e 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreCommon.vsprops @@ -1,30 +1,30 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioPropertySheet - ProjectType="Visual C++" - Version="8.00" - Name="JavaScriptCoreCommon" - > - <Tool - Name="VCCLCompilerTool" - AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../parser/;../../bytecompiler/;../../jit/;../../runtime/;../../bytecode/;../../interpreter/;../../wtf/;../../profiler;../../assembler/;../../debugger/;../../wrec/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";"$(WebKitLibrariesDir)\include\private";../../../icu/include;"$(WebKitOutputDir)\include";"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility"" - PreprocessorDefinitions="__STD_C" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="gdi32.lib oleaut32.lib winmm.lib icuin$(LibraryConfigSuffix).lib icuuc$(LibraryConfigSuffix).lib pthreadVC2$(LibraryConfigSuffix).lib WTF$(WebKitConfigSuffix).lib" - OutputFile="$(OutDir)\$(ProjectName)$(WebKitDLLConfigSuffix).dll" - ModuleDefinitionFile="JavaScriptCore$(WebKitDLLConfigSuffix).def" - /> - <Tool - Name="VCPostBuildEventTool" - CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\private\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\parser\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\runtime\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\bytecode\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\interpreter\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\assembler\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wrec\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\jit\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\debugger\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\create_hash_table" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"

mkdir 2>NUL "$(OutDir)\JavaScriptCore.resources"
xcopy /y /d "$(ProjectDir)..\$(ProjectName).resources\*" "$(OutDir)\$(ProjectName).resources"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
" - /> - <Tool - Name="VCPreBuildEventTool" - CommandLine="set PATH=%SystemDrive%\cygwin\bin;%PATH%
if exist "$(WebKitOutputDir)\buildfailed" grep XX$(ProjectName)XX "$(WebKitOutputDir)\buildfailed"
if errorlevel 1 exit 1
echo XX$(ProjectName)XX > "$(WebKitOutputDir)\buildfailed"

bash "$(WebKitLibrariesDir)\tools\scripts\auto-version.sh" "$(IntDir)"
" - /> - <Tool - Name="VCPreLinkEventTool" - CommandLine="if not exist "$(WebKitOutputDir)\public\sym" mkdir "$(WebKitOutputDir)\public\sym"" - /> -</VisualStudioPropertySheet> +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="JavaScriptCoreCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\DerivedSources\";../../;../../API/;../../pcre/;../../parser/;../../bytecompiler/;../../jit/;../../runtime/;../../bytecode/;../../interpreter/;../../wtf/;../../profiler;../../assembler/;../../debugger/;../../wrec/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";"$(WebKitLibrariesDir)\include\private";../../../icu/include;"$(WebKitOutputDir)\include";"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders";"$(WebKitLibrariesDir)\Include\CoreFoundation\OSXCompatibilityHeaders\GNUCompatibility""
+ PreprocessorDefinitions="__STD_C"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="gdi32.lib oleaut32.lib winmm.lib icuin$(LibraryConfigSuffix).lib icuuc$(LibraryConfigSuffix).lib pthreadVC2$(LibraryConfigSuffix).lib WTF$(WebKitConfigSuffix).lib"
+ OutputFile="$(OutDir)\$(ProjectName)$(WebKitDLLConfigSuffix).dll"
+ ModuleDefinitionFile="JavaScriptCore.def"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="mkdir 2>NUL "$(WebKitOutputDir)\include\private\JavaScriptCore"

xcopy /y /d "$(ProjectDir)\..\..\wtf\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wtf\unicode\icu\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\parser\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\runtime\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\VM\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\bytecode\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\interpreter\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\assembler\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\wrec\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\jit\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\debugger\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\profiler\*.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\create_hash_table" "$(WebKitOutputDir)\include\private\JavaScriptCore"
xcopy /y /d "$(ProjectDir)\..\..\pcre\pcre.h" "$(WebKitOutputDir)\include\private\JavaScriptCore"

mkdir 2>NUL "$(OutDir)\JavaScriptCore.resources"
xcopy /y /d "$(ProjectDir)..\$(ProjectName).resources\*" "$(OutDir)\$(ProjectName).resources"

if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"
"
+ />
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine="%SystemDrive%\cygwin\bin\which.exe bash
if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
cmd /c
if exist "$(WebKitOutputDir)\buildfailed" grep XX$(ProjectName)XX "$(WebKitOutputDir)\buildfailed"
if errorlevel 1 exit 1
echo XX$(ProjectName)XX > "$(WebKitOutputDir)\buildfailed"

bash "$(WebKitLibrariesDir)\tools\scripts\auto-version.sh" "$(IntDir)"
"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ CommandLine="if not exist "$(WebKitOutputDir)\public\sym" mkdir "$(WebKitOutputDir)\public\sym""
+ />
+</VisualStudioPropertySheet>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.make b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.make index 9fd7ad4..92479bb 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.make +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.make @@ -7,6 +7,7 @@ all: xcopy /y /d "..\..\API\JavaScript.h" "$(WEBKITOUTPUTDIR)\include\JavaScriptCore" xcopy /y /d "..\..\API\JSBase.h" "$(WEBKITOUTPUTDIR)\include\JavaScriptCore" xcopy /y /d "..\..\API\JSContextRef.h" "$(WEBKITOUTPUTDIR)\include\JavaScriptCore" + xcopy /y /d "..\..\API\JSContextRefPrivate.h" "$(WEBKITOUTPUTDIR)\include\JavaScriptCore" xcopy /y /d "..\..\API\JSObjectRef.h" "$(WEBKITOUTPUTDIR)\include\JavaScriptCore" xcopy /y /d "..\..\API\JSStringRef.h" "$(WEBKITOUTPUTDIR)\include\JavaScriptCore" xcopy /y /d "..\..\API\JSStringRefCF.h" "$(WEBKITOUTPUTDIR)\include\JavaScriptCore" diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.vcproj index 954045e..7d5ca69 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCoreGenerated.vcproj @@ -1,53 +1,53 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioProject - ProjectType="Visual C++" - Version="8.00" - Name="JavaScriptCoreGenerated" - ProjectGUID="{4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}" - RootNamespace="JavaScriptCoreGenerated" - Keyword="MakeFileProj" - > - <Platforms> - <Platform - Name="Win32" - /> - </Platforms> - <ToolFiles> - </ToolFiles> - <Configurations> - <Configuration - Name="Release|Win32" - OutputDirectory="$(WebKitOutputDir)\lib" - IntermediateDirectory="$(WebKitOutputDir)\obj\$(ProjectName)\$(ConfigurationName)" - ConfigurationType="0" - > - <Tool - Name="VCNMakeTool" - BuildCommandLine="set PATH=%SystemDrive%\cygwin\bin;%PATH%

nmake /nologo -f JavaScriptCoreGenerated.make" - ReBuildCommandLine="set PATH=%SystemDrive%\cygwin\bin;%PATH%

nmake /nologo -f JavaScriptCoreGenerated.make clean
nmake -f JavaScriptCoreGenerated.make" - CleanCommandLine="set PATH=%SystemDrive%\cygwin\bin;%PATH%

nmake /nologo -f JavaScriptCoreGenerated.make clean" - Output="" - PreprocessorDefinitions="WIN32;NDEBUG" - IncludeSearchPath="" - ForcedIncludes="" - AssemblySearchPath="" - ForcedUsingAssemblies="" - CompileAsManaged="" - /> - </Configuration> - </Configurations> - <References> - </References> - <Files> - <File - RelativePath=".\build-generated-files.sh" - > - </File> - <File - RelativePath=".\JavaScriptCoreGenerated.make" - > - </File> - </Files> - <Globals> - </Globals> -</VisualStudioProject> +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioProject
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="JavaScriptCoreGenerated"
+ ProjectGUID="{4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}"
+ RootNamespace="JavaScriptCoreGenerated"
+ Keyword="MakeFileProj"
+ >
+ <Platforms>
+ <Platform
+ Name="Win32"
+ />
+ </Platforms>
+ <ToolFiles>
+ </ToolFiles>
+ <Configurations>
+ <Configuration
+ Name="all|Win32"
+ OutputDirectory="$(WebKitOutputDir)\lib"
+ IntermediateDirectory="$(WebKitOutputDir)\obj\$(ProjectName)\$(ConfigurationName)"
+ ConfigurationType="0"
+ >
+ <Tool
+ Name="VCNMakeTool"
+ BuildCommandLine="%SystemDrive%\cygwin\bin\which.exe bash
if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
cmd /c

nmake /nologo -f JavaScriptCoreGenerated.make"
+ ReBuildCommandLine="%SystemDrive%\cygwin\bin\which.exe bash
if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
cmd /c

nmake /nologo -f JavaScriptCoreGenerated.make clean
nmake -f JavaScriptCoreGenerated.make"
+ CleanCommandLine="%SystemDrive%\cygwin\bin\which.exe bash
if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
cmd /c

nmake /nologo -f JavaScriptCoreGenerated.make clean"
+ Output=""
+ PreprocessorDefinitions="WIN32;NDEBUG"
+ IncludeSearchPath=""
+ ForcedIncludes=""
+ AssemblySearchPath=""
+ ForcedUsingAssemblies=""
+ CompileAsManaged=""
+ />
+ </Configuration>
+ </Configurations>
+ <References>
+ </References>
+ <Files>
+ <File
+ RelativePath=".\build-generated-files.sh"
+ >
+ </File>
+ <File
+ RelativePath=".\JavaScriptCoreGenerated.make"
+ >
+ </File>
+ </Files>
+ <Globals>
+ </Globals>
+</VisualStudioProject>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def deleted file mode 100644 index 65998ca..0000000 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCore/JavaScriptCore_debug.def +++ /dev/null @@ -1,280 +0,0 @@ -LIBRARY "JavaScriptCore_debug" - -EXPORTS - ?from@UString@JSC@@SA?AV12@N@Z - ?nonInlineNaN@JSC@@YANXZ - ?synthesizePrototype@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z - ?toObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z - ?toThisObjectSlowCase@JSValue@JSC@@ABEPAVJSObject@2@PAVExecState@2@@Z - ??0Collator@WTF@@QAE@PBD@Z - ??0Debugger@JSC@@QAE@XZ - ??0DropAllLocks@JSLock@JSC@@QAE@W4JSLockBehavior@2@@Z - ??0InternalFunction@JSC@@IAE@PAVJSGlobalData@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@ABVIdentifier@1@@Z - ??0JSByteArray@JSC@@QAE@PAVExecState@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@PAVByteArray@4@PBUClassInfo@1@@Z - ??0JSFunction@JSC@@QAE@PAVExecState@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V61@ABVArgList@1@@Z@Z - ??0Mutex@WTF@@QAE@XZ - ??0PrototypeFunction@JSC@@QAE@PAVExecState@1@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V41@ABVArgList@1@@Z@Z - ??0PrototypeFunction@JSC@@QAE@PAVExecState@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@HABVIdentifier@1@P6I?AVJSValue@1@0PAVJSObject@1@V61@ABVArgList@1@@Z@Z - ??0RefCountedLeakCounter@WTF@@QAE@PBD@Z - ??0StringObject@JSC@@QAE@PAVExecState@1@V?$PassRefPtr@VStructure@JSC@@@WTF@@ABVUString@1@@Z - ??0Structure@JSC@@AAE@VJSValue@1@ABVTypeInfo@1@@Z - ??0ThreadCondition@WTF@@QAE@XZ - ??0UString@JSC@@QAE@PBD@Z - ??0UString@JSC@@QAE@PB_WH@Z - ??1CString@JSC@@QAE@XZ - ??1ClientData@JSGlobalData@JSC@@UAE@XZ - ??1Collator@WTF@@QAE@XZ - ??1Debugger@JSC@@UAE@XZ - ??1DropAllLocks@JSLock@JSC@@QAE@XZ - ??1JSGlobalData@JSC@@QAE@XZ - ??1JSGlobalObject@JSC@@UAE@XZ - ??1Mutex@WTF@@QAE@XZ - ??1RefCountedLeakCounter@WTF@@QAE@XZ - ??1Structure@JSC@@QAE@XZ - ??1ThreadCondition@WTF@@QAE@XZ - ??2JSCell@JSC@@SAPAXIPAVExecState@1@@Z - ??2JSGlobalObject@JSC@@SAPAXIPAVJSGlobalData@1@@Z - ??4UString@JSC@@QAEAAV01@PBD@Z - ??8JSC@@YA_NABVUString@0@0@Z - ?UTF8String@UString@JSC@@QBE?AVCString@2@_N@Z - ?add@Identifier@JSC@@SA?AV?$PassRefPtr@URep@UString@JSC@@@WTF@@PAVExecState@2@PBD@Z - ?add@PropertyNameArray@JSC@@QAEXPAURep@UString@2@@Z - ?addPropertyTransition@Structure@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@PAV12@ABVIdentifier@2@IPAVJSCell@2@AAI@Z - ?addPropertyTransitionToExistingStructure@Structure@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@PAV12@ABVIdentifier@2@IPAVJSCell@2@AAI@Z - ?addPropertyWithoutTransition@Structure@JSC@@QAEIABVIdentifier@2@IPAVJSCell@2@@Z - ?addSlowCase@Identifier@JSC@@CA?AV?$PassRefPtr@URep@UString@JSC@@@WTF@@PAVExecState@2@PAURep@UString@2@@Z - ?addSlowCase@Identifier@JSC@@CA?AV?$PassRefPtr@URep@UString@JSC@@@WTF@@PAVJSGlobalData@2@PAURep@UString@2@@Z - ?allocate@Heap@JSC@@QAEPAXI@Z - ?allocatePropertyStorage@JSObject@JSC@@QAEXII@Z - ?append@UString@JSC@@QAEAAV12@ABV12@@Z - ?append@UString@JSC@@QAEAAV12@PBD@Z - ?ascii@UString@JSC@@QBEPADXZ - ?attach@Debugger@JSC@@QAEXPAVJSGlobalObject@2@@Z - ?broadcast@ThreadCondition@WTF@@QAEXXZ - ?calculatedFunctionName@DebuggerCallFrame@JSC@@QBE?AVUString@2@XZ - ?call@JSC@@YA?AVJSValue@1@PAVExecState@1@V21@W4CallType@1@ABTCallData@1@1ABVArgList@1@@Z - ?callOnMainThread@WTF@@YAXP6AXPAX@Z0@Z - ?changePrototypeTransition@Structure@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@PAV12@VJSValue@2@@Z - ?checkSameIdentifierTable@Identifier@JSC@@CAXPAVExecState@2@PAURep@UString@2@@Z - ?checkSameIdentifierTable@Identifier@JSC@@CAXPAVJSGlobalData@2@PAURep@UString@2@@Z - ?checkSyntax@JSC@@YA?AVCompletion@1@PAVExecState@1@ABVSourceCode@1@@Z - ?classInfo@InternalFunction@JSC@@UBEPBUClassInfo@2@XZ - ?classInfo@JSCell@JSC@@UBEPBUClassInfo@2@XZ - ?className@JSObject@JSC@@UBE?AVUString@2@XZ - ?collate@Collator@WTF@@QBE?AW4Result@12@PB_WI0I@Z - ?collect@Heap@JSC@@QAE_NXZ - ?computeHash@Rep@UString@JSC@@SAIPBDH@Z - ?computeHash@Rep@UString@JSC@@SAIPB_WH@Z - ?construct@JSC@@YAPAVJSObject@1@PAVExecState@1@VJSValue@1@W4ConstructType@1@ABTConstructData@1@ABVArgList@1@@Z - ?constructArray@JSC@@YAPAVJSArray@1@PAVExecState@1@ABVArgList@1@@Z - ?constructEmptyArray@JSC@@YAPAVJSArray@1@PAVExecState@1@@Z - ?constructEmptyObject@JSC@@YAPAVJSObject@1@PAVExecState@1@@Z - ?constructFunction@JSC@@YAPAVJSObject@1@PAVExecState@1@ABVArgList@1@ABVIdentifier@1@ABVUString@1@H@Z - ?convertUTF16ToUTF8@Unicode@WTF@@YA?AW4ConversionResult@12@PAPB_WPB_WPAPADPAD_N@Z - ?copyParameters@FunctionBodyNode@JSC@@QAEPAVIdentifier@2@XZ - ?create@ByteArray@WTF@@SA?AV?$PassRefPtr@VByteArray@WTF@@@2@I@Z - ?create@FunctionBodyNode@JSC@@SA?AV?$PassRefPtr@VFunctionBodyNode@JSC@@@WTF@@PAVJSGlobalData@2@PAVSourceElements@2@PAV?$Vector@U?$pair@VIdentifier@JSC@@I@std@@$0A@@4@PAV?$Vector@PAVFuncDeclNode@JSC@@$0A@@4@ABVSourceCode@2@IH@Z - ?create@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@_N@Z - ?create@OpaqueJSString@@SA?AV?$PassRefPtr@UOpaqueJSString@@@WTF@@ABVUString@JSC@@@Z - ?create@Rep@UString@JSC@@SA?AV?$PassRefPtr@URep@UString@JSC@@@WTF@@PA_WHV?$PassRefPtr@V?$CrossThreadRefCounted@V?$OwnFastMallocPtr@_W@WTF@@@WTF@@@5@@Z - ?createEmptyString@SmallStrings@JSC@@AAEXPAVJSGlobalData@2@@Z - ?createInheritorID@JSObject@JSC@@AAEPAVStructure@2@XZ - ?createLeaked@JSGlobalData@JSC@@SA?AV?$PassRefPtr@VJSGlobalData@JSC@@@WTF@@XZ - ?createStructure@JSByteArray@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@VJSValue@2@@Z - ?createTable@HashTable@JSC@@ABEXPAVJSGlobalData@2@@Z - ?createThread@WTF@@YAIP6APAXPAX@Z0@Z - ?createThread@WTF@@YAIP6APAXPAX@Z0PBD@Z - ?currentThread@WTF@@YAIXZ - ?currentTime@WTF@@YANXZ - ?decrement@RefCountedLeakCounter@WTF@@QAEXXZ - ?defaultValue@JSObject@JSC@@UBE?AVJSValue@2@PAVExecState@2@W4PreferredPrimitiveType@2@@Z - ?defineGetter@JSGlobalObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAVJSObject@2@@Z - ?defineGetter@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAV12@@Z - ?defineSetter@JSGlobalObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAVJSObject@2@@Z - ?defineSetter@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@PAV12@@Z - ?deleteOwnedPtr@WTF@@YAXPAUHBITMAP__@@@Z - ?deleteOwnedPtr@WTF@@YAXPAUHRGN__@@@Z - ?deleteProperty@JSCell@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@@Z - ?deleteProperty@JSCell@JSC@@UAE_NPAVExecState@2@I@Z - ?deleteProperty@JSObject@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@@Z - ?deleteProperty@JSObject@JSC@@UAE_NPAVExecState@2@I@Z - ?deleteProperty@JSVariableObject@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@@Z - ?deleteProperty@StringObject@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@@Z - ?deleteTable@HashTable@JSC@@QBEXXZ - ?despecifyDictionaryFunction@Structure@JSC@@QAEXABVIdentifier@2@@Z - ?despecifyFunctionTransition@Structure@JSC@@SA?AV?$PassRefPtr@VStructure@JSC@@@WTF@@PAV12@ABVIdentifier@2@@Z - ?destroy@Heap@JSC@@QAEXXZ - ?destroy@Rep@UString@JSC@@QAEXXZ - ?detach@Debugger@JSC@@UAEXPAVJSGlobalObject@2@@Z - ?detachThread@WTF@@YAXI@Z - ?equal@Identifier@JSC@@SA_NPBURep@UString@2@PBD@Z - ?equal@JSC@@YA_NPBURep@UString@1@0@Z - ?evaluate@DebuggerCallFrame@JSC@@QBE?AVJSValue@2@ABVUString@2@AAV32@@Z - ?evaluate@JSC@@YA?AVCompletion@1@PAVExecState@1@AAVScopeChain@1@ABVSourceCode@1@VJSValue@1@@Z - ?exclude@Profile@JSC@@QAEXPBVProfileNode@2@@Z - ?fastCalloc@WTF@@YAPAXII@Z - ?fastFree@WTF@@YAXPAX@Z - ?fastMalloc@WTF@@YAPAXI@Z - ?fastRealloc@WTF@@YAPAXPAXI@Z - ?fastZeroedMalloc@WTF@@YAPAXI@Z - ?fillGetterPropertySlot@JSObject@JSC@@QAEXAAVPropertySlot@2@PAVJSValue@2@@Z - ?finishParsing@FunctionBodyNode@JSC@@QAEXPAVIdentifier@2@I@Z - ?focus@Profile@JSC@@QAEXPBVProfileNode@2@@Z - ?from@UString@JSC@@SA?AV12@H@Z - ?from@UString@JSC@@SA?AV12@I@Z - ?functionName@DebuggerCallFrame@JSC@@QBEPBVUString@2@XZ - ?get@Structure@JSC@@QAEIPBURep@UString@2@AAIAAPAVJSCell@2@@Z - ?getCallData@JSCell@JSC@@UAE?AW4CallType@2@AATCallData@2@@Z - ?getConstructData@JSCell@JSC@@UAE?AW4ConstructType@2@AATConstructData@2@@Z - ?getJSNumber@JSCell@JSC@@UAE?AVJSValue@2@XZ - ?getObject@JSCell@JSC@@QAEPAVJSObject@2@XZ - ?getOwnPropertySlot@JSCell@JSC@@EAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertySlot@2@@Z - ?getOwnPropertySlot@JSCell@JSC@@EAE_NPAVExecState@2@IAAVPropertySlot@2@@Z - ?getOwnPropertySlot@JSObject@JSC@@UAE_NPAVExecState@2@IAAVPropertySlot@2@@Z - ?getOwnPropertySlot@JSString@JSC@@EAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertySlot@2@@Z - ?getOwnPropertySlot@JSString@JSC@@EAE_NPAVExecState@2@IAAVPropertySlot@2@@Z - ?getOwnPropertySlot@StringObject@JSC@@UAE_NPAVExecState@2@ABVIdentifier@2@AAVPropertySlot@2@@Z - ?getOwnPropertySlot@StringObject@JSC@@UAE_NPAVExecState@2@IAAVPropertySlot@2@@Z - ?getPrimitiveNumber@JSAPIValueWrapper@JSC@@UAE_NPAVExecState@2@AANAAVJSValue@2@@Z - ?getPrimitiveNumber@JSObject@JSC@@UAE_NPAVExecState@2@AANAAVJSValue@2@@Z - ?getPrimitiveNumber@JSString@JSC@@EAE_NPAVExecState@2@AANAAVJSValue@2@@Z - ?getPropertyAttributes@JSObject@JSC@@UBE_NPAVExecState@2@ABVIdentifier@2@AAI@Z - ?getPropertyAttributes@JSVariableObject@JSC@@UBE_NPAVExecState@2@ABVIdentifier@2@AAI@Z - ?getPropertyNames@JSObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@@Z - ?getPropertyNames@JSVariableObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@@Z - ?getPropertyNames@StringObject@JSC@@UAEXPAVExecState@2@AAVPropertyNameArray@2@@Z - ?getSlice@ArgList@JSC@@QBEXHAAV12@@Z - ?getString@JSCell@JSC@@QBE?AVUString@2@XZ - ?getString@JSCell@JSC@@QBE_NAAVUString@2@@Z - ?getUInt32@JSCell@JSC@@UBE_NAAI@Z - ?globalExec@JSGlobalObject@JSC@@UAEPAVExecState@2@XZ - ?globalObjectCount@Heap@JSC@@QAEIXZ - ?hasInstance@JSObject@JSC@@UAE_NPAVExecState@2@VJSValue@2@1@Z - ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@ABVIdentifier@2@@Z - ?hasProperty@JSObject@JSC@@QBE_NPAVExecState@2@I@Z - ?heap@Heap@JSC@@SAPAV12@VJSValue@2@@Z - ?increment@RefCountedLeakCounter@WTF@@QAEXXZ - ?init@JSGlobalObject@JSC@@AAEXPAVJSObject@2@@Z - ?initializeMainThread@WTF@@YAXXZ - ?initializeThreading@JSC@@YAXXZ - ?initializeThreading@WTF@@YAXXZ - ?is8Bit@UString@JSC@@QBE_NXZ - ?isBusy@Heap@JSC@@QAE_NXZ - ?isDynamicScope@JSGlobalObject@JSC@@UBE_NXZ - ?isGetterSetter@JSCell@JSC@@UBE_NXZ - ?isHostFunction@FunctionBodyNode@JSC@@QBE_NXZ - ?isMainThread@WTF@@YA_NXZ - ?isVariableObject@JSVariableObject@JSC@@UBE_NXZ - ?jsNumberCell@JSC@@YA?AVJSValue@1@PAVExecState@1@N@Z - ?jsOwnedString@JSC@@YAPAVJSString@1@PAVJSGlobalData@1@ABVUString@1@@Z - ?jsRegExpCompile@@YAPAUJSRegExp@@PB_WHW4JSRegExpIgnoreCaseOption@@W4JSRegExpMultilineOption@@PAIPAPBD@Z - ?jsRegExpExecute@@YAHPBUJSRegExp@@PB_WHHPAHH@Z - ?jsRegExpFree@@YAXPAUJSRegExp@@@Z - ?jsString@JSC@@YAPAVJSString@1@PAVJSGlobalData@1@ABVUString@1@@Z - ?lock@JSLock@JSC@@SAXW4JSLockBehavior@2@@Z - ?lock@Mutex@WTF@@QAEXXZ - ?lockAtomicallyInitializedStaticMutex@WTF@@YAXXZ - ?lookupGetter@JSObject@JSC@@UAE?AVJSValue@2@PAVExecState@2@ABVIdentifier@2@@Z - ?lookupSetter@JSObject@JSC@@UAE?AVJSValue@2@PAVExecState@2@ABVIdentifier@2@@Z - ?markChildren@JSGlobalObject@JSC@@UAEXAAVMarkStack@2@@Z - ?markChildren@JSObject@JSC@@UAEXAAVMarkStack@2@@Z - ?markChildren@JSWrapperObject@JSC@@UAEXAAVMarkStack@2@@Z - ?materializePropertyMap@Structure@JSC@@AAEXXZ - ?name@InternalFunction@JSC@@QAEABVUString@2@PAVJSGlobalData@2@@Z - ?objectCount@Heap@JSC@@QAEIXZ - ?objectProtoFuncToString@JSC@@YI?AVJSValue@1@PAVExecState@1@PAVJSObject@1@V21@ABVArgList@1@@Z - ?parse@Parser@JSC@@AAEXPAVJSGlobalData@2@PAHPAVUString@2@@Z - ?parseDateFromNullTerminatedCharacters@WTF@@YANPBD@Z - ?primaryHeapBegin@Heap@JSC@@QAE?AV?$CollectorHeapIterator@$0A@@2@XZ - ?primaryHeapEnd@Heap@JSC@@QAE?AV?$CollectorHeapIterator@$0A@@2@XZ - ?profiler@Profiler@JSC@@SAPAV12@XZ - ?protect@Heap@JSC@@QAEXVJSValue@2@@Z - ?protectedGlobalObjectCount@Heap@JSC@@QAEIXZ - ?protectedObjectCount@Heap@JSC@@QAEIXZ - ?protectedObjectTypeCounts@Heap@JSC@@QAEPAV?$HashCountedSet@PBDU?$PtrHash@PBD@WTF@@U?$HashTraits@PBD@2@@WTF@@XZ - ?put@JSCell@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@VJSValue@2@AAVPutPropertySlot@2@@Z - ?put@JSCell@JSC@@UAEXPAVExecState@2@IVJSValue@2@@Z - ?put@JSGlobalObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@VJSValue@2@AAVPutPropertySlot@2@@Z - ?put@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@VJSValue@2@AAVPutPropertySlot@2@@Z - ?put@JSObject@JSC@@UAEXPAVExecState@2@IVJSValue@2@@Z - ?put@StringObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@VJSValue@2@AAVPutPropertySlot@2@@Z - ?putDirectFunction@JSObject@JSC@@QAEXPAVExecState@2@PAVInternalFunction@2@I@Z - ?putWithAttributes@JSGlobalObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@VJSValue@2@I@Z - ?putWithAttributes@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@VJSValue@2@I@Z - ?putWithAttributes@JSObject@JSC@@UAEXPAVExecState@2@ABVIdentifier@2@VJSValue@2@I_NAAVPutPropertySlot@2@@Z - ?putWithAttributes@JSObject@JSC@@UAEXPAVExecState@2@IVJSValue@2@I@Z - ?randomNumber@WTF@@YANXZ - ?recordExtraCost@Heap@JSC@@AAEXI@Z - ?releaseStack@MarkStack@JSC@@CAXPAXI@Z - ?reset@ParserArena@JSC@@QAEXXZ - ?reset@TimeoutChecker@JSC@@QAEXXZ - ?restoreAll@Profile@JSC@@QAEXXZ - ?retrieveCaller@Interpreter@JSC@@QBE?AVJSValue@2@PAVExecState@2@PAVInternalFunction@2@@Z - ?retrieveLastCaller@Interpreter@JSC@@QBEXPAVExecState@2@AAH1AAVUString@2@AAVJSValue@2@@Z - ?setDumpsGeneratedCode@BytecodeGenerator@JSC@@SAX_N@Z - ?setGCProtectNeedsLocking@Heap@JSC@@QAEXXZ - ?setLoc@StatementNode@JSC@@QAEXHH@Z - ?setMainThreadCallbacksPaused@WTF@@YAX_N@Z - ?setOrderLowerFirst@Collator@WTF@@QAEX_N@Z - ?setUpStaticFunctionSlot@JSC@@YAXPAVExecState@1@PBVHashEntry@1@PAVJSObject@1@ABVIdentifier@1@AAVPropertySlot@1@@Z - ?sharedBuffer@Rep@UString@JSC@@QAEPAV?$CrossThreadRefCounted@V?$OwnFastMallocPtr@_W@WTF@@@WTF@@XZ - ?signal@ThreadCondition@WTF@@QAEXXZ - ?slowAppend@MarkedArgumentBuffer@JSC@@AAEXVJSValue@2@@Z - ?startIgnoringLeaks@Structure@JSC@@SAXXZ - ?startProfiling@Profiler@JSC@@QAEXPAVExecState@2@ABVUString@2@@Z - ?stopIgnoringLeaks@Structure@JSC@@SAXXZ - ?stopProfiling@Profiler@JSC@@QAE?AV?$PassRefPtr@VProfile@JSC@@@WTF@@PAVExecState@2@ABVUString@2@@Z - ?strtod@WTF@@YANPBDPAPAD@Z - ?substr@UString@JSC@@QBE?AV12@HH@Z - ?thisObject@DebuggerCallFrame@JSC@@QBEPAVJSObject@2@XZ - ?throwError@JSC@@YAPAVJSObject@1@PAVExecState@1@W4ErrorType@1@@Z - ?throwError@JSC@@YAPAVJSObject@1@PAVExecState@1@W4ErrorType@1@ABVUString@1@@Z - ?throwError@JSC@@YAPAVJSObject@1@PAVExecState@1@W4ErrorType@1@PBD@Z - ?timedWait@ThreadCondition@WTF@@QAE_NAAVMutex@2@N@Z - ?tlsKeyCount@WTF@@YAAAJXZ - ?tlsKeys@WTF@@YAPAKXZ - ?toBoolean@JSAPIValueWrapper@JSC@@UBE_NPAVExecState@2@@Z - ?toBoolean@JSObject@JSC@@UBE_NPAVExecState@2@@Z - ?toBoolean@JSString@JSC@@EBE_NPAVExecState@2@@Z - ?toInt32SlowCase@JSC@@YAHNAA_N@Z - ?toNumber@JSAPIValueWrapper@JSC@@UBENPAVExecState@2@@Z - ?toNumber@JSObject@JSC@@UBENPAVExecState@2@@Z - ?toNumber@JSString@JSC@@EBENPAVExecState@2@@Z - ?toObject@JSAPIValueWrapper@JSC@@UBEPAVJSObject@2@PAVExecState@2@@Z - ?toObject@JSObject@JSC@@UBEPAV12@PAVExecState@2@@Z - ?toObject@JSString@JSC@@EBEPAVJSObject@2@PAVExecState@2@@Z - ?toPrimitive@JSAPIValueWrapper@JSC@@UBE?AVJSValue@2@PAVExecState@2@W4PreferredPrimitiveType@2@@Z - ?toPrimitive@JSString@JSC@@EBE?AVJSValue@2@PAVExecState@2@W4PreferredPrimitiveType@2@@Z - ?toStrictUInt32@UString@JSC@@QBEIPA_N@Z - ?toString@JSAPIValueWrapper@JSC@@UBE?AVUString@2@PAVExecState@2@@Z - ?toString@JSObject@JSC@@UBE?AVUString@2@PAVExecState@2@@Z - ?toString@JSString@JSC@@EBE?AVUString@2@PAVExecState@2@@Z - ?toString@StringObject@JSC@@EBE?AVUString@2@PAVExecState@2@@Z - ?toThisJSString@JSCell@JSC@@UAEPAVJSString@2@PAVExecState@2@@Z - ?toThisJSString@JSString@JSC@@EAEPAV12@PAVExecState@2@@Z - ?toThisJSString@StringObject@JSC@@EAEPAVJSString@2@PAVExecState@2@@Z - ?toThisObject@JSCell@JSC@@UBEPAVJSObject@2@PAVExecState@2@@Z - ?toThisObject@JSObject@JSC@@UBEPAV12@PAVExecState@2@@Z - ?toThisObject@JSString@JSC@@EBEPAVJSObject@2@PAVExecState@2@@Z - ?toThisString@JSCell@JSC@@UBE?AVUString@2@PAVExecState@2@@Z - ?toThisString@JSString@JSC@@EBE?AVUString@2@PAVExecState@2@@Z - ?toThisString@StringObject@JSC@@EBE?AVUString@2@PAVExecState@2@@Z - ?toUInt32@UString@JSC@@QBEIPA_N@Z - ?toUInt32@UString@JSC@@QBEIPA_N_N@Z - ?toUInt32SlowCase@JSC@@YAINAA_N@Z - ?tryFastCalloc@WTF@@YAPAXII@Z - ?tryLock@Mutex@WTF@@QAE_NXZ - ?type@DebuggerCallFrame@JSC@@QBE?AW4Type@12@XZ - ?unlock@JSLock@JSC@@SAXW4JSLockBehavior@2@@Z - ?unlock@Mutex@WTF@@QAEXXZ - ?unlockAtomicallyInitializedStaticMutex@WTF@@YAXXZ - ?unprotect@Heap@JSC@@QAEXVJSValue@2@@Z - ?unwrappedObject@JSObject@JSC@@UAEPAV12@XZ - ?wait@ThreadCondition@WTF@@QAEXAAVMutex@2@@Z - ?waitForThreadCompletion@WTF@@YAHIPAPAX@Z - WTFLog - WTFLogVerbose - WTFReportArgumentAssertionFailure - WTFReportAssertionFailure - WTFReportAssertionFailureWithMessage - WTFReportError diff --git a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCoreSubmit.sln b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCoreSubmit.sln index fe3a7ba..142e5bc 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCoreSubmit.sln +++ b/JavaScriptCore/JavaScriptCore.vcproj/JavaScriptCoreSubmit.sln @@ -20,6 +20,7 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "jsc", "jsc\jsc.vcproj", "{C EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
+ Debug_All|Win32 = Debug_All|Win32
Debug_Internal|Win32 = Debug_Internal|Win32
Debug|Win32 = Debug|Win32
Release_PGOInstrument|Win32 = Release_PGOInstrument|Win32
@@ -27,6 +28,8 @@ Global Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
+ {011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug_All|Win32.Build.0 = Debug_All|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug_Internal|Win32.ActiveCfg = Debug_Internal|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug_Internal|Win32.Build.0 = Debug_Internal|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Debug|Win32.ActiveCfg = Debug|Win32
@@ -37,6 +40,8 @@ Global {011D10F1-B656-4A1B-A0C3-3842F02122C5}.Release_PGOOptimize|Win32.Build.0 = Release_PGOOptimize|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Release|Win32.ActiveCfg = Release|Win32
{011D10F1-B656-4A1B-A0C3-3842F02122C5}.Release|Win32.Build.0 = Release|Win32
+ {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug_All|Win32.Build.0 = Debug_All|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug_Internal|Win32.ActiveCfg = Debug_Internal|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug_Internal|Win32.Build.0 = Debug_Internal|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Debug|Win32.ActiveCfg = Debug|Win32
@@ -47,16 +52,20 @@ Global {AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release_PGOOptimize|Win32.Build.0 = Release|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release|Win32.ActiveCfg = Release|Win32
{AA8A5A85-592B-4357-BC60-E0E91E026AF6}.Release|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_Internal|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_Internal|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOInstrument|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOInstrument|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOOptimize|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOOptimize|Win32.Build.0 = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release|Win32.ActiveCfg = Release|Win32
- {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release|Win32.Build.0 = Release|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_All|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_All|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_Internal|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug_Internal|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Debug|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOInstrument|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOInstrument|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOOptimize|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release_PGOOptimize|Win32.Build.0 = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release|Win32.ActiveCfg = all|Win32
+ {4FF5BA11-59EC-4C24-8F52-F235C2E7D43A}.Release|Win32.Build.0 = all|Win32
+ {C59E5129-B453-49B7-A52B-1E104715F76E}.Debug_All|Win32.ActiveCfg = Debug_All|Win32
+ {C59E5129-B453-49B7-A52B-1E104715F76E}.Debug_All|Win32.Build.0 = Debug_All|Win32
{C59E5129-B453-49B7-A52B-1E104715F76E}.Debug_Internal|Win32.ActiveCfg = Debug_Internal|Win32
{C59E5129-B453-49B7-A52B-1E104715F76E}.Debug_Internal|Win32.Build.0 = Debug_Internal|Win32
{C59E5129-B453-49B7-A52B-1E104715F76E}.Debug|Win32.ActiveCfg = Debug|Win32
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj index 6ed89e5..78f507a 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTF.vcproj @@ -172,6 +172,58 @@ Name="VCPostBuildEventTool"
/>
</Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="4"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_internal.vsprops;.\WTFCommon.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_all.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
</Configurations>
<References>
</References>
@@ -233,14 +285,6 @@ >
</File>
<File
- RelativePath="..\..\wtf\DateMath.cpp"
- >
- </File>
- <File
- RelativePath="..\..\wtf\DateMath.h"
- >
- </File>
- <File
RelativePath="..\..\wtf\Deque.h"
>
</File>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTFCommon.vsprops b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTFCommon.vsprops index 20b32f3..d78ff43 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTFCommon.vsprops +++ b/JavaScriptCore/JavaScriptCore.vcproj/WTF/WTFCommon.vsprops @@ -1,26 +1,26 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioPropertySheet - ProjectType="Visual C++" - Version="8.00" - Name="WTFCommon" - OutputDirectory="$(WebKitOutputDir)\lib" - > - <Tool - Name="VCCLCompilerTool" - AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\$(ConfigurationName)\DerivedSources\";../../;"../../os-win32/";../../pcre/;../../parser/;../../wtf/;../../wtf/unicode/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;../../bindings;../../bindings/c;../../bindings/jni;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads"" - PreprocessorDefinitions="__STD_C" - /> - <Tool - Name="VCLibrarianTool" - AdditionalDependencies="user32.lib" - OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix).lib" - /> - <Tool - Name="VCPostBuildEventTool" - CommandLine="if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"" - /> - <Tool - Name="VCPreBuildEventTool" - CommandLine="set PATH=%SystemDrive%\cygwin\bin;%PATH%" - /> -</VisualStudioPropertySheet> +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="WTFCommon"
+ OutputDirectory="$(WebKitOutputDir)\lib"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""$(WebKitOutputDir)\obj\JavaScriptCore\$(ConfigurationName)\DerivedSources\";../../;"../../os-win32/";../../pcre/;../../parser/;../../wtf/;../../wtf/unicode/;"$(WebKitLibrariesDir)\include";"$(WebKitLibrariesDir)\include\icu";../../../icu/include;../../bindings;../../bindings/c;../../bindings/jni;"$(WebKitOutputDir)\include\JavaScriptCore";"$(WebKitLibrariesDir)\include\pthreads""
+ PreprocessorDefinitions="__STD_C"
+ />
+ <Tool
+ Name="VCLibrarianTool"
+ AdditionalDependencies="user32.lib"
+ OutputFile="$(OutDir)\$(ProjectName)$(WebKitConfigSuffix).lib"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed""
+ />
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine="%SystemDrive%\cygwin\bin\which.exe bash
if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
cmd /c"
+ />
+</VisualStudioPropertySheet>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/jsc/jsc.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/jsc/jsc.vcproj index ce2fe04..76c1550 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/jsc/jsc.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/jsc/jsc.vcproj @@ -199,6 +199,128 @@ Name="VCPostBuildEventTool"
/>
</Configuration>
+ <Configuration
+ Name="Debug_CFLite|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_wincairo.vsprops;.\jscCommon.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_internal.vsprops;.\jscCommon.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_all.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
</Configurations>
<References>
</References>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/jsc/jscCommon.vsprops b/JavaScriptCore/JavaScriptCore.vcproj/jsc/jscCommon.vsprops index 3a1e42e..1a8f8b6 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/jsc/jscCommon.vsprops +++ b/JavaScriptCore/JavaScriptCore.vcproj/jsc/jscCommon.vsprops @@ -1,25 +1,25 @@ -<?xml version="1.0" encoding="Windows-1252"?> -<VisualStudioPropertySheet - ProjectType="Visual C++" - Version="8.00" - Name="jscCommon" - > - <Tool - Name="VCCLCompilerTool" - AdditionalIncludeDirectories=""$(WebKitOutputDir)\include";"$(WebKitOutputDir)\obj\JavaScriptCore\$(ConfigurationName)\DerivedSources\";../../;"../../os-win32/";../../pcre/;../../assembler/;../../wrec/;../../parser/;../../runtime/;../../VM/;../../bytecode/;../../interpreter/;../../wtf/;../../debugger/;../../bytecompiler/;../../profiler;"$(WebKitLibrariesDir)\include\icu";"$(WebKitLibrariesDir)\include\pthreads";../../../icu/include;"$(WebKitLibrariesDir)\include";../../jit/" - PreprocessorDefinitions="__STD_C" - /> - <Tool - Name="VCLinkerTool" - AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib WTF$(WebKitConfigSuffix).lib icuin$(LibraryConfigSuffix).lib icuuc$(LibraryConfigSuffix).lib winmm.lib pthreadVC2$(LibraryConfigSuffix).lib user32.lib" - SubSystem="1" - /> - <Tool - Name="VCPostBuildEventTool" - CommandLine="if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"

mkdir 2>NUL "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt40.dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt40.dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\CoreFoundation.resources" xcopy /y /d /e /i "$(WebKitLibrariesDir)\bin\CoreFoundation.resources" "$(WebKitOutputDir)\bin\CoreFoundation.resources"
if exist "$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\objc$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\objc$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\ASL$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\ASL$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"

cmd /c
" - /> - <Tool - Name="VCPreBuildEventTool" - CommandLine="set PATH=%SystemDrive%\cygwin\bin;%PATH%
if exist "$(WebKitOutputDir)\buildfailed" grep XX$(ProjectName)XX "$(WebKitOutputDir)\buildfailed"
if errorlevel 1 exit 1
echo XX$(ProjectName)XX > "$(WebKitOutputDir)\buildfailed"
" - /> -</VisualStudioPropertySheet> +<?xml version="1.0" encoding="Windows-1252"?>
+<VisualStudioPropertySheet
+ ProjectType="Visual C++"
+ Version="8.00"
+ Name="jscCommon"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ AdditionalIncludeDirectories=""$(WebKitOutputDir)\include";"$(WebKitOutputDir)\obj\JavaScriptCore\$(ConfigurationName)\DerivedSources\";../../;"../../os-win32/";../../pcre/;../../assembler/;../../wrec/;../../parser/;../../runtime/;../../VM/;../../bytecode/;../../interpreter/;../../wtf/;../../debugger/;../../bytecompiler/;../../profiler;"$(WebKitLibrariesDir)\include\icu";"$(WebKitLibrariesDir)\include\pthreads";../../../icu/include;"$(WebKitLibrariesDir)\include";../../jit/"
+ PreprocessorDefinitions="__STD_C"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib WTF$(WebKitConfigSuffix).lib icuin$(LibraryConfigSuffix).lib icuuc$(LibraryConfigSuffix).lib winmm.lib pthreadVC2$(LibraryConfigSuffix).lib user32.lib"
+ SubSystem="1"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ CommandLine="if exist "$(WebKitOutputDir)\buildfailed" del "$(WebKitOutputDir)\buildfailed"

mkdir 2>NUL "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt40.dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt40.dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuin40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuuc40$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt42.dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt42.dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icudt42$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuin42$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\icuuc42$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\CoreFoundation$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\CoreFoundation.resources" xcopy /y /d /e /i "$(WebKitLibrariesDir)\bin\CoreFoundation.resources" "$(WebKitOutputDir)\bin\CoreFoundation.resources"
if exist "$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\pthreadVC2$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\objc$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\objc$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"
if exist "$(WebKitLibrariesDir)\bin\ASL$(LibraryConfigSuffix).dll" xcopy /y /d "$(WebKitLibrariesDir)\bin\ASL$(LibraryConfigSuffix).dll" "$(WebKitOutputDir)\bin"

cmd /c
"
+ />
+ <Tool
+ Name="VCPreBuildEventTool"
+ CommandLine="%SystemDrive%\cygwin\bin\which.exe bash
if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
cmd /c
if exist "$(WebKitOutputDir)\buildfailed" grep XX$(ProjectName)XX "$(WebKitOutputDir)\buildfailed"
if errorlevel 1 exit 1
echo XX$(ProjectName)XX > "$(WebKitOutputDir)\buildfailed"
"
+ />
+</VisualStudioPropertySheet>
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapi.vcproj b/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapi.vcproj index ef45c5b..9581e54 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapi.vcproj +++ b/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapi.vcproj @@ -18,7 +18,7 @@ <Configuration
Name="Debug|Win32"
ConfigurationType="1"
- InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug.vsprops;.\testapiCommon.vsprops"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug.vsprops;.\testapiCommon.vsprops;..\JavaScriptCore\JavaScriptCoreCF.vsprops"
CharacterSet="1"
>
<Tool
@@ -79,7 +79,7 @@ <Configuration
Name="Release|Win32"
ConfigurationType="1"
- InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\testapiCommon.vsprops"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\testapiCommon.vsprops;..\JavaScriptCore\JavaScriptCoreCF.vsprops"
CharacterSet="1"
WholeProgramOptimization="1"
>
@@ -141,7 +141,191 @@ <Configuration
Name="Debug_Internal|Win32"
ConfigurationType="1"
- InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_internal.vsprops;.\testapiCommon.vsprops"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_internal.vsprops;.\testapiCommon.vsprops;..\JavaScriptCore\JavaScriptCoreCF.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_CFLite|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_wincairo.vsprops;.\testapiCommon.vsprops;..\JavaScriptCore\JavaScriptCoreCFLite.vsprops"
+ CharacterSet="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Release_CFLite|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\release.vsprops;.\testapiCommon.vsprops;..\JavaScriptCore\JavaScriptCoreCFLite.vsprops"
+ CharacterSet="1"
+ WholeProgramOptimization="1"
+ >
+ <Tool
+ Name="VCPreBuildEventTool"
+ />
+ <Tool
+ Name="VCCustomBuildTool"
+ />
+ <Tool
+ Name="VCXMLDataGeneratorTool"
+ />
+ <Tool
+ Name="VCWebServiceProxyGeneratorTool"
+ />
+ <Tool
+ Name="VCMIDLTool"
+ />
+ <Tool
+ Name="VCCLCompilerTool"
+ />
+ <Tool
+ Name="VCManagedResourceCompilerTool"
+ />
+ <Tool
+ Name="VCResourceCompilerTool"
+ />
+ <Tool
+ Name="VCPreLinkEventTool"
+ />
+ <Tool
+ Name="VCLinkerTool"
+ />
+ <Tool
+ Name="VCALinkTool"
+ />
+ <Tool
+ Name="VCManifestTool"
+ />
+ <Tool
+ Name="VCXDCMakeTool"
+ />
+ <Tool
+ Name="VCBscMakeTool"
+ />
+ <Tool
+ Name="VCFxCopTool"
+ />
+ <Tool
+ Name="VCAppVerifierTool"
+ />
+ <Tool
+ Name="VCWebDeploymentTool"
+ />
+ <Tool
+ Name="VCPostBuildEventTool"
+ />
+ </Configuration>
+ <Configuration
+ Name="Debug_All|Win32"
+ ConfigurationType="1"
+ InheritedPropertySheets="$(WebKitLibrariesDir)\tools\vsprops\common.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_internal.vsprops;.\testapiCommon.vsprops;..\JavaScriptCore\JavaScriptCoreCF.vsprops;$(WebKitLibrariesDir)\tools\vsprops\debug_all.vsprops"
CharacterSet="1"
>
<Tool
@@ -230,6 +414,30 @@ CompileAs="2"
/>
</FileConfiguration>
+ <FileConfiguration
+ Name="Debug_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Release_CFLite|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ CompileAs="2"
+ />
+ </FileConfiguration>
+ <FileConfiguration
+ Name="Debug_All|Win32"
+ >
+ <Tool
+ Name="VCCLCompilerTool"
+ CompileAs="2"
+ />
+ </FileConfiguration>
</File>
<File
RelativePath="..\..\API\tests\testapi.js"
diff --git a/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapiCommon.vsprops b/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapiCommon.vsprops index 2a36c18..7c6d126 100644 --- a/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapiCommon.vsprops +++ b/JavaScriptCore/JavaScriptCore.vcproj/testapi/testapiCommon.vsprops @@ -12,7 +12,7 @@ /> <Tool Name="VCLinkerTool" - AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib WTF$(WebKitConfigSuffix).lib CoreFoundation$(LibraryConfigSuffix).lib pthreadVC2$(LibraryConfigSuffix).lib icuin$(LibraryConfigSuffix).lib icuuc$(LibraryConfigSuffix).lib" + AdditionalDependencies="JavaScriptCore$(WebKitDLLConfigSuffix).lib WTF$(WebKitConfigSuffix).lib pthreadVC2$(LibraryConfigSuffix).lib icuin$(LibraryConfigSuffix).lib icuuc$(LibraryConfigSuffix).lib" SubSystem="1" /> <Tool @@ -21,6 +21,6 @@ /> <Tool Name="VCPreBuildEventTool" - CommandLine="set PATH=%SystemDrive%\cygwin\bin;%PATH%
if exist "$(WebKitOutputDir)\buildfailed" grep XX$(ProjectName)XX "$(WebKitOutputDir)\buildfailed"
if errorlevel 1 exit 1
echo XX$(ProjectName)XX > "$(WebKitOutputDir)\buildfailed"
" + CommandLine="%SystemDrive%\cygwin\bin\which.exe bash
if errorlevel 1 set PATH=%SystemDrive%\cygwin\bin;%PATH%
cmd /c
if exist "$(WebKitOutputDir)\buildfailed" grep XX$(ProjectName)XX "$(WebKitOutputDir)\buildfailed"
if errorlevel 1 exit 1
echo XX$(ProjectName)XX > "$(WebKitOutputDir)\buildfailed"
" /> </VisualStudioPropertySheet> diff --git a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj index 6c3d49f..e766243 100644 --- a/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj +++ b/JavaScriptCore/JavaScriptCore.xcodeproj/project.pbxproj @@ -44,11 +44,31 @@ 0B4D7E630F319AC800AD7E58 /* TypeTraits.h in Headers */ = {isa = PBXBuildFile; fileRef = 0B4D7E620F319AC800AD7E58 /* TypeTraits.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0BDFFAE00FC6192900D69EF4 /* CrossThreadRefCounted.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BDFFAD40FC6171000D69EF4 /* CrossThreadRefCounted.h */; settings = {ATTRIBUTES = (Private, ); }; }; 0BDFFAE10FC6193100D69EF4 /* OwnFastMallocPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 0BDFFAD10FC616EC00D69EF4 /* OwnFastMallocPtr.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC0894D50FAFBA2D00001865 /* JSAPIValueWrapper.cpp */; }; + 140566D1107EC267005DBC8D /* JSStaticScopeObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7E42C190E3938830065A544 /* JSStaticScopeObject.cpp */; }; + 140566D6107EC271005DBC8D /* JSFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A85E0255597D01FF60F7 /* JSFunction.cpp */; }; 140B7D1D0DC69AF7009C42B8 /* JSActivation.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14DA818F0D99FD2000B0A4FB /* JSActivation.cpp */; }; 140D17D70E8AD4A9000CD17D /* JSBasePrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 140D17D60E8AD4A9000CD17D /* JSBasePrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; 141211310A48794D00480255 /* JavaScriptCore.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 932F5BD90822A1C700736975 /* JavaScriptCore.framework */; }; 141211340A48795800480255 /* minidom.c in Sources */ = {isa = PBXBuildFile; fileRef = 141211020A48780900480255 /* minidom.c */; }; + 1420BE7B10AA6DDB00F455D2 /* WeakRandom.h in Headers */ = {isa = PBXBuildFile; fileRef = 1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1421359B0A677F4F00A8195E /* JSBase.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1421359A0A677F4F00A8195E /* JSBase.cpp */; }; + 14280823107EC02C0013E7B2 /* Debugger.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8580255597D01FF60F7 /* Debugger.cpp */; }; + 1428082D107EC0570013E7B2 /* CallData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCA62DFE0E2826230004F30D /* CallData.cpp */; }; + 1428082E107EC0570013E7B2 /* ConstructData.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCA62DFF0E2826310004F30D /* ConstructData.cpp */; }; + 1428083A107EC0750013E7B2 /* RegisterFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1429D85B0ED218E900B89619 /* RegisterFile.cpp */; }; + 14280841107EC0930013E7B2 /* RegExp.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A87D0255597D01FF60F7 /* RegExp.cpp */; }; + 14280842107EC0930013E7B2 /* RegExpConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD202BD0E1706A7002C7E82 /* RegExpConstructor.cpp */; }; + 14280843107EC0930013E7B2 /* RegExpObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A87B0255597D01FF60F7 /* RegExpObject.cpp */; }; + 14280844107EC0930013E7B2 /* RegExpPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD202BF0E1706A7002C7E82 /* RegExpPrototype.cpp */; }; + 14280850107EC0D70013E7B2 /* Operations.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8770255597D01FF60F7 /* Operations.cpp */; }; + 14280855107EC0E70013E7B2 /* GetterSetter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E9B80E184545000F9297 /* GetterSetter.cpp */; }; + 1428085D107EC0F80013E7B2 /* JSNumberCell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E9B90E184580000F9297 /* JSNumberCell.cpp */; }; + 14280863107EC11A0013E7B2 /* BooleanConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC7952320E15EB5600A898AB /* BooleanConstructor.cpp */; }; + 14280864107EC11A0013E7B2 /* BooleanObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8500255597D01FF60F7 /* BooleanObject.cpp */; }; + 14280865107EC11A0013E7B2 /* BooleanPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC7952340E15EB5600A898AB /* BooleanPrototype.cpp */; }; + 14280870107EC1340013E7B2 /* JSWrapperObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65C7A1710A8EAACB00FA37EA /* JSWrapperObject.cpp */; }; + 14280875107EC13E0013E7B2 /* JSLock.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65EA4C99092AF9E20093D800 /* JSLock.cpp */; }; 1429D77C0ED20D7300B89619 /* Interpreter.h in Headers */ = {isa = PBXBuildFile; fileRef = 1429D77B0ED20D7300B89619 /* Interpreter.h */; settings = {ATTRIBUTES = (Private, ); }; }; 1429D7D40ED2128200B89619 /* Interpreter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1429D7D30ED2128200B89619 /* Interpreter.cpp */; settings = {COMPILER_FLAGS = "-fno-var-tracking"; }; }; 1429D8780ED21ACD00B89619 /* ExceptionHelpers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1429D8770ED21ACD00B89619 /* ExceptionHelpers.cpp */; }; @@ -67,6 +87,7 @@ 1429DAC00ED263E700B89619 /* WRECParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1429DABE0ED263E700B89619 /* WRECParser.cpp */; }; 1429DAE00ED2645B00B89619 /* WRECGenerator.h in Headers */ = {isa = PBXBuildFile; fileRef = 1429DADE0ED2645B00B89619 /* WRECGenerator.h */; }; 1429DAE10ED2645B00B89619 /* WRECGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1429DADF0ED2645B00B89619 /* WRECGenerator.cpp */; }; + 142D3939103E4560007DCB52 /* NumericStrings.h in Headers */ = {isa = PBXBuildFile; fileRef = 142D3938103E4560007DCB52 /* NumericStrings.h */; settings = {ATTRIBUTES = (Private, ); }; }; 143A97E60A4A06E200456B66 /* CoreFoundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 6560A4CF04B3B3E7008AE952 /* CoreFoundation.framework */; }; 1440057F0A5335640005F061 /* JSNode.c in Sources */ = {isa = PBXBuildFile; fileRef = 1440F6420A4F8B6A0005F061 /* JSNode.c */; }; 144005CB0A5338D10005F061 /* JSNode.h in Headers */ = {isa = PBXBuildFile; fileRef = 1440F6410A4F8B6A0005F061 /* JSNode.h */; }; @@ -80,12 +101,64 @@ 1440F8920A508B100005F061 /* JSCallbackFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1440F8900A508B100005F061 /* JSCallbackFunction.cpp */; }; 1440F8AF0A508D200005F061 /* JSCallbackConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1440F8AD0A508D200005F061 /* JSCallbackConstructor.cpp */; }; 1440FCE40A51E46B0005F061 /* JSClassRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1440FCE20A51E46B0005F061 /* JSClassRef.cpp */; }; + 14469DD7107EC79E00650446 /* dtoa.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 651F6412039D5B5F0078395C /* dtoa.cpp */; }; + 14469DDE107EC7E700650446 /* Lookup.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8680255597D01FF60F7 /* Lookup.cpp */; }; + 14469DDF107EC7E700650446 /* MathObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A86A0255597D01FF60F7 /* MathObject.cpp */; }; + 14469DE0107EC7E700650446 /* NativeErrorConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E9080E1839DB000F9297 /* NativeErrorConstructor.cpp */; }; + 14469DE1107EC7E700650446 /* NativeErrorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E90A0E1839DB000F9297 /* NativeErrorPrototype.cpp */; }; + 14469DE2107EC7E700650446 /* NumberConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C20E16D4E900A06E92 /* NumberConstructor.cpp */; }; + 14469DE3107EC7E700650446 /* NumberObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8700255597D01FF60F7 /* NumberObject.cpp */; }; + 14469DE4107EC7E700650446 /* NumberPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C40E16D4E900A06E92 /* NumberPrototype.cpp */; }; + 14469DE5107EC7E700650446 /* ObjectConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C60E16D4E900A06E92 /* ObjectConstructor.cpp */; }; + 14469DE6107EC7E700650446 /* ObjectPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */; }; + 14469DE7107EC7E700650446 /* PropertyNameArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65400C0F0A69BAF200509887 /* PropertyNameArray.cpp */; }; + 14469DE8107EC7E700650446 /* PropertySlot.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65621E6B089E859700760F35 /* PropertySlot.cpp */; }; + 14469DE9107EC7E700650446 /* PrototypeFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC257DF10E1F53740016B6C9 /* PrototypeFunction.cpp */; }; + 14469DEA107EC7E700650446 /* ScopeChain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 9374D3A8038D9D74008635CE /* ScopeChain.cpp */; }; + 14469DEB107EC7E700650446 /* StringConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC18C3C00E16EE3300B34460 /* StringConstructor.cpp */; }; + 14469DEC107EC7E700650446 /* StringObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC18C3C20E16EE3300B34460 /* StringObject.cpp */; }; + 14469DED107EC7E700650446 /* StringPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC18C3C50E16EE3300B34460 /* StringPrototype.cpp */; }; + 14469DEE107EC7E700650446 /* UString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8850255597D01FF60F7 /* UString.cpp */; }; 146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 146AAB370B66A94400E55F16 /* JSStringRefCF.cpp */; }; 147B83AC0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B83AA0E6DB8C9004775A4 /* BatchedTransitionOptimizer.h */; }; 147B84630E6DE6B1004775A4 /* PutPropertySlot.h in Headers */ = {isa = PBXBuildFile; fileRef = 147B84620E6DE6B1004775A4 /* PutPropertySlot.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 147F39BD107EC37600427A48 /* ArgList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCF605110E203EF800B9A64D /* ArgList.cpp */; }; + 147F39BE107EC37600427A48 /* Arguments.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC257DE50E1F51C50016B6C9 /* Arguments.cpp */; }; + 147F39BF107EC37600427A48 /* ArrayConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC7952060E15E8A800A898AB /* ArrayConstructor.cpp */; }; + 147F39C0107EC37600427A48 /* ArrayPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A84D0255597D01FF60F7 /* ArrayPrototype.cpp */; }; + 147F39C1107EC37600427A48 /* CommonIdentifiers.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65EA73620BAE35D1001BB560 /* CommonIdentifiers.cpp */; }; + 147F39C2107EC37600427A48 /* Completion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 969A09220ED1E09C00F1F681 /* Completion.cpp */; }; + 147F39C3107EC37600427A48 /* DateConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD203450E17135E002C7E82 /* DateConstructor.cpp */; }; + 147F39C4107EC37600427A48 /* DateConversion.cpp in Sources */ = {isa = PBXBuildFile; fileRef = D21202280AD4310C00ED79B6 /* DateConversion.cpp */; }; + 147F39C5107EC37600427A48 /* DateInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC1166000E1997B1008066DD /* DateInstance.cpp */; }; + 147F39C6107EC37600427A48 /* DatePrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BCD203470E17135E002C7E82 /* DatePrototype.cpp */; }; + 147F39C7107EC37600427A48 /* Error.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC337BEA0E1B00CB0076918A /* Error.cpp */; }; + 147F39C8107EC37600427A48 /* ErrorConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E9040E1839DB000F9297 /* ErrorConstructor.cpp */; }; + 147F39C9107EC37600427A48 /* ErrorInstance.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E98A0E183E38000F9297 /* ErrorInstance.cpp */; }; + 147F39CA107EC37600427A48 /* ErrorPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E9060E1839DB000F9297 /* ErrorPrototype.cpp */; }; + 147F39CB107EC37600427A48 /* FunctionConstructor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC2680C00E16D4E900A06E92 /* FunctionConstructor.cpp */; }; + 147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A85C0255597D01FF60F7 /* FunctionPrototype.cpp */; }; + 147F39CD107EC37600427A48 /* GlobalEvalFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC257DED0E1F52ED0016B6C9 /* GlobalEvalFunction.cpp */; }; + 147F39CE107EC37600427A48 /* Identifier.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 933A349D038AE80F008635CE /* Identifier.cpp */; }; + 147F39CF107EC37600427A48 /* InternalFunction.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC9BB95B0E19680600DF8855 /* InternalFunction.cpp */; }; + 147F39D0107EC37600427A48 /* JSArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93ADFCE60CCBD7AC00D30B08 /* JSArray.cpp */; }; + 147F39D1107EC37600427A48 /* JSCell.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC7F8FBA0E19D1EF008632C0 /* JSCell.cpp */; }; + 147F39D2107EC37600427A48 /* JSGlobalObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14DE0D680D02431400AACCA2 /* JSGlobalObject.cpp */; }; + 147F39D3107EC37600427A48 /* JSImmediate.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14760863099C633800437128 /* JSImmediate.cpp */; }; + 147F39D4107EC37600427A48 /* JSObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC22A3980E16E14800AF21C8 /* JSObject.cpp */; }; + 147F39D5107EC37600427A48 /* JSString.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC02E9B60E1842FA000F9297 /* JSString.cpp */; }; + 147F39D6107EC37600427A48 /* JSValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8870255597D01FF60F7 /* JSValue.cpp */; }; + 147F39D7107EC37600427A48 /* JSVariableObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */; }; 1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B74C0A43032800517CFC /* JSStringRef.cpp */; }; 1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 1482B7E20A43076000517CFC /* JSObjectRef.cpp */; }; + 148CD1D8108CF902008163C6 /* JSContextRefPrivate.h in Headers */ = {isa = PBXBuildFile; fileRef = 148CD1D7108CF902008163C6 /* JSContextRefPrivate.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 148F21A3107EC5310042EC2C /* Grammar.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65FB3F4809D11B2400F49DEB /* Grammar.cpp */; }; + 148F21AA107EC53A0042EC2C /* BytecodeGenerator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 969A07200ED1CE3300F1F681 /* BytecodeGenerator.cpp */; }; + 148F21B0107EC5410042EC2C /* Lexer.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8650255597D01FF60F7 /* Lexer.cpp */; }; + 148F21B7107EC5470042EC2C /* Nodes.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A86D0255597D01FF60F7 /* Nodes.cpp */; }; + 148F21BC107EC54D0042EC2C /* Parser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93F0B3A909BB4DC00068FCE3 /* Parser.cpp */; }; 149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 149559ED0DDCDDF700648087 /* DebuggerCallFrame.cpp */; }; + 14A1563210966365006FA260 /* DateInstanceCache.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A1563010966365006FA260 /* DateInstanceCache.h */; settings = {ATTRIBUTES = (Private, ); }; }; 14A23D750F4E1ABB0023CDAD /* JITStubs.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14A23D6C0F4E19CE0023CDAD /* JITStubs.cpp */; }; 14A42E3F0F4F60EE00599099 /* TimeoutChecker.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14A42E3D0F4F60EE00599099 /* TimeoutChecker.cpp */; }; 14A42E400F4F60EE00599099 /* TimeoutChecker.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A42E3E0F4F60EE00599099 /* TimeoutChecker.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -95,7 +168,11 @@ 14BD5A300A3E91F600BAF59C /* JSContextRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A290A3E91F600BAF59C /* JSContextRef.cpp */; }; 14BD5A320A3E91F600BAF59C /* JSValueRef.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 14BD5A2B0A3E91F600BAF59C /* JSValueRef.cpp */; }; 14C5242B0F5355E900BA3D04 /* JITStubs.h in Headers */ = {isa = PBXBuildFile; fileRef = 14A6581A0F4E36F4000150FD /* JITStubs.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 14F3488F0E95EF8A003648BC /* CollectorHeapIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F3488E0E95EF8A003648BC /* CollectorHeapIterator.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 14E9D17B107EC469004DDA21 /* JSGlobalObjectFunctions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = BC756FC60E2031B200DE7D12 /* JSGlobalObjectFunctions.cpp */; }; + 14F3488F0E95EF8A003648BC /* CollectorHeapIterator.h in Headers */ = {isa = PBXBuildFile; fileRef = 14F3488E0E95EF8A003648BC /* CollectorHeapIterator.h */; settings = {ATTRIBUTES = (); }; }; + 14F8BA3E107EC886009892DC /* FastMalloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65E217B908E7EECC0023E5F6 /* FastMalloc.cpp */; }; + 14F8BA43107EC88C009892DC /* TCSystemAlloc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6541BD7008E80A17002CBEE7 /* TCSystemAlloc.cpp */; }; + 14F8BA4F107EC899009892DC /* Collector.cpp in Sources */ = {isa = PBXBuildFile; fileRef = F692A8520255597D01FF60F7 /* Collector.cpp */; }; 180B9B080F16D94F009BDBC5 /* CurrentTime.h in Headers */ = {isa = PBXBuildFile; fileRef = 180B9AF00F16C569009BDBC5 /* CurrentTime.h */; settings = {ATTRIBUTES = (Private, ); }; }; 180B9BFE0F16E94D009BDBC5 /* CurrentTime.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 180B9AEF0F16C569009BDBC5 /* CurrentTime.cpp */; }; 1C61516C0EBAC7A00031376F /* ProfilerServer.mm in Sources */ = {isa = PBXBuildFile; fileRef = 1C61516A0EBAC7A00031376F /* ProfilerServer.mm */; settings = {COMPILER_FLAGS = "-fno-strict-aliasing"; }; }; @@ -109,9 +186,9 @@ 5D5D8AB60E0D0A7200F9C692 /* jsc in Copy Into Framework */ = {isa = PBXBuildFile; fileRef = 932F5BE10822A1C700736975 /* jsc */; }; 5D5D8AD10E0D0EBE00F9C692 /* libedit.dylib in Frameworks */ = {isa = PBXBuildFile; fileRef = 5D5D8AD00E0D0EBE00F9C692 /* libedit.dylib */; }; 5D6A566B0F05995500266145 /* Threading.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 5D6A566A0F05995500266145 /* Threading.cpp */; }; - 5DE6E5B30E1728EC00180407 /* create_hash_table in Headers */ = {isa = PBXBuildFile; fileRef = F692A8540255597D01FF60F7 /* create_hash_table */; settings = {ATTRIBUTES = (Private, ); }; }; - 6507D29E0E871E5E00D7D896 /* TypeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6507D2970E871E4A00D7D896 /* TypeInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; - 659126BD0BDD1728001921FB /* AllInOneFile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 659126BC0BDD1728001921FB /* AllInOneFile.cpp */; }; + 5DE6E5B30E1728EC00180407 /* create_hash_table in Headers */ = {isa = PBXBuildFile; fileRef = F692A8540255597D01FF60F7 /* create_hash_table */; settings = {ATTRIBUTES = (); }; }; + 6507D29E0E871E5E00D7D896 /* JSTypeInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 655EB29B10CE2581001A990E /* NodesCodegen.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 655EB29A10CE2581001A990E /* NodesCodegen.cpp */; }; 65DFC93308EA173A00F7300B /* HashTable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65DFC92D08EA173A00F7300B /* HashTable.cpp */; }; 65FDE49C0BDD1D4A00E80111 /* Assertions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 65E217B808E7EECC0023E5F6 /* Assertions.cpp */; settings = {COMPILER_FLAGS = "-Wno-missing-format-attribute"; }; }; 7E2ADD8E0E79AAD500D50C51 /* CharacterClassConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = 7E2ADD8D0E79AAD500D50C51 /* CharacterClassConstructor.h */; }; @@ -132,6 +209,8 @@ 86ADD1450FDDEA980006EEC2 /* ARMv7Assembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */; }; 86ADD1460FDDEA980006EEC2 /* MacroAssemblerARMv7.h in Headers */ = {isa = PBXBuildFile; fileRef = 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */; }; 86C36EEA0EE1289D00B3DF59 /* MacroAssembler.h in Headers */ = {isa = PBXBuildFile; fileRef = 86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */; }; + 86CA032E1038E8440028A609 /* Executable.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CA032D1038E8440028A609 /* Executable.cpp */; }; + 86CAFEE31035DDE60028A609 /* Executable.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CAFEE21035DDE60028A609 /* Executable.h */; settings = {ATTRIBUTES = (); }; }; 86CC85A10EE79A4700288682 /* JITInlineMethods.h in Headers */ = {isa = PBXBuildFile; fileRef = 86CC85A00EE79A4700288682 /* JITInlineMethods.h */; }; 86CC85A30EE79B7400288682 /* JITCall.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CC85A20EE79B7400288682 /* JITCall.cpp */; }; 86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */; }; @@ -155,7 +234,7 @@ 905B02AE0E28640F006DF882 /* RefCountedLeakCounter.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 905B02AD0E28640F006DF882 /* RefCountedLeakCounter.cpp */; }; 90D3469C0E285280009492EE /* RefCountedLeakCounter.h in Headers */ = {isa = PBXBuildFile; fileRef = 90D3469B0E285280009492EE /* RefCountedLeakCounter.h */; settings = {ATTRIBUTES = (Private, ); }; }; 93052C340FB792190048FDC3 /* ParserArena.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 93052C320FB792190048FDC3 /* ParserArena.cpp */; }; - 93052C350FB792190048FDC3 /* ParserArena.h in Headers */ = {isa = PBXBuildFile; fileRef = 93052C330FB792190048FDC3 /* ParserArena.h */; settings = {ATTRIBUTES = (Private, ); }; }; + 93052C350FB792190048FDC3 /* ParserArena.h in Headers */ = {isa = PBXBuildFile; fileRef = 93052C330FB792190048FDC3 /* ParserArena.h */; settings = {ATTRIBUTES = (); }; }; 930754C108B0F68000AB3056 /* pcre_compile.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 930754BF08B0F68000AB3056 /* pcre_compile.cpp */; }; 930754D008B0F74600AB3056 /* pcre_tables.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 930754CE08B0F74500AB3056 /* pcre_tables.cpp */; }; 930754EB08B0F78500AB3056 /* pcre_exec.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 930754E908B0F78500AB3056 /* pcre_exec.cpp */; settings = {COMPILER_FLAGS = "-fno-move-loop-invariants"; }; }; @@ -206,12 +285,15 @@ A7A1F7AC0F252B3C00E184E2 /* ByteArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7A1F7AA0F252B3C00E184E2 /* ByteArray.cpp */; }; A7A1F7AD0F252B3C00E184E2 /* ByteArray.h in Headers */ = {isa = PBXBuildFile; fileRef = A7A1F7AB0F252B3C00E184E2 /* ByteArray.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7B48F490EE8936F00DCBDB6 /* ExecutableAllocator.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */; }; + A7C2217810C7479400F97913 /* JSZombie.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7C2216B10C7469C00F97913 /* JSZombie.cpp */; }; A7C530E4102A3813005BC741 /* MarkStackPosix.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7C530E3102A3813005BC741 /* MarkStackPosix.cpp */; }; + A7D649AA1015224E009B2E1B /* PossiblyNull.h in Headers */ = {isa = PBXBuildFile; fileRef = A7D649A91015224E009B2E1B /* PossiblyNull.h */; settings = {ATTRIBUTES = (Private, ); }; }; A7E2EA6B0FB460CF00601F06 /* LiteralParser.h in Headers */ = {isa = PBXBuildFile; fileRef = A7E2EA690FB460CF00601F06 /* LiteralParser.h */; }; A7E2EA6C0FB460CF00601F06 /* LiteralParser.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7E2EA6A0FB460CF00601F06 /* LiteralParser.cpp */; }; A7F9935F0FD7325100A0B2D0 /* JSONObject.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F9935D0FD7325100A0B2D0 /* JSONObject.h */; }; A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */; }; - A7F9949B0FD746A300A0B2D0 /* JSONObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = A7F9949A0FD746A300A0B2D0 /* JSONObject.lut.h */; }; + A7FB60A4103F7DC20017A286 /* PropertyDescriptor.cpp in Sources */ = {isa = PBXBuildFile; fileRef = A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */; }; + A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */ = {isa = PBXBuildFile; fileRef = A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC02E90D0E1839DB000F9297 /* ErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9050E1839DB000F9297 /* ErrorConstructor.h */; }; BC02E90F0E1839DB000F9297 /* ErrorPrototype.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9070E1839DB000F9297 /* ErrorPrototype.h */; }; BC02E9110E1839DB000F9297 /* NativeErrorConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC02E9090E1839DB000F9297 /* NativeErrorConstructor.h */; }; @@ -240,7 +322,7 @@ BC18C3FC0E16F5CD00B34460 /* Deque.h in Headers */ = {isa = PBXBuildFile; fileRef = 5186111D0CC824830081412B /* Deque.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C3FD0E16F5CD00B34460 /* DisallowCType.h in Headers */ = {isa = PBXBuildFile; fileRef = 938C4F6B0CA06BCE00D9310A /* DisallowCType.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C3FE0E16F5CD00B34460 /* dtoa.h in Headers */ = {isa = PBXBuildFile; fileRef = 651F6413039D5B5F0078395C /* dtoa.h */; settings = {ATTRIBUTES = (Private, ); }; }; - BC18C4000E16F5CD00B34460 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; }; + BC18C4000E16F5CD00B34460 /* ExceptionHelpers.h in Headers */ = {isa = PBXBuildFile; fileRef = A72701B30DADE94900E548D7 /* ExceptionHelpers.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C4020E16F5CD00B34460 /* FastMalloc.h in Headers */ = {isa = PBXBuildFile; fileRef = 65E217BA08E7EECC0023E5F6 /* FastMalloc.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C4030E16F5CD00B34460 /* Forward.h in Headers */ = {isa = PBXBuildFile; fileRef = 935AF46909E9D9DB00ACD1D8 /* Forward.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C4040E16F5CD00B34460 /* FunctionConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C10E16D4E900A06E92 /* FunctionConstructor.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -293,7 +375,7 @@ BC18C43B0E16F5CD00B34460 /* MathExtras.h in Headers */ = {isa = PBXBuildFile; fileRef = BCF6553B0A2048DE0038A194 /* MathExtras.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C43C0E16F5CD00B34460 /* MathObject.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A86B0255597D01FF60F7 /* MathObject.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C43E0E16F5CD00B34460 /* MessageQueue.h in Headers */ = {isa = PBXBuildFile; fileRef = E1EE798B0D6CA53D00FEA3BA /* MessageQueue.h */; settings = {ATTRIBUTES = (Private, ); }; }; - BC18C43F0E16F5CD00B34460 /* Nodes.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A86E0255597D01FF60F7 /* Nodes.h */; settings = {ATTRIBUTES = (Private, ); }; }; + BC18C43F0E16F5CD00B34460 /* Nodes.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A86E0255597D01FF60F7 /* Nodes.h */; settings = {ATTRIBUTES = (); }; }; BC18C4400E16F5CD00B34460 /* Noncopyable.h in Headers */ = {isa = PBXBuildFile; fileRef = 9303F5690991190000AD71B8 /* Noncopyable.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C4410E16F5CD00B34460 /* NumberConstructor.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680C30E16D4E900A06E92 /* NumberConstructor.h */; }; BC18C4420E16F5CD00B34460 /* NumberConstructor.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */; }; @@ -304,7 +386,7 @@ BC18C4480E16F5CD00B34460 /* Operations.h in Headers */ = {isa = PBXBuildFile; fileRef = F692A8780255597D01FF60F7 /* Operations.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C4490E16F5CD00B34460 /* OwnArrayPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 9303F5A409911A5800AD71B8 /* OwnArrayPtr.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C44A0E16F5CD00B34460 /* OwnPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 9303F567099118FA00AD71B8 /* OwnPtr.h */; settings = {ATTRIBUTES = (Private, ); }; }; - BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F0B3AA09BB4DC00068FCE3 /* Parser.h */; settings = {ATTRIBUTES = (Private, ); }; }; + BC18C44B0E16F5CD00B34460 /* Parser.h in Headers */ = {isa = PBXBuildFile; fileRef = 93F0B3AA09BB4DC00068FCE3 /* Parser.h */; settings = {ATTRIBUTES = (); }; }; BC18C44C0E16F5CD00B34460 /* PassRefPtr.h in Headers */ = {isa = PBXBuildFile; fileRef = 6580F795094070560082C219 /* PassRefPtr.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C44D0E16F5CD00B34460 /* pcre.h in Headers */ = {isa = PBXBuildFile; fileRef = 6541720F039E08B90058BFEB /* pcre.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC18C44E0E16F5CD00B34460 /* pcre_internal.h in Headers */ = {isa = PBXBuildFile; fileRef = 93E26BE508B1517100F85226 /* pcre_internal.h */; }; @@ -351,8 +433,8 @@ BC18C5260E16FCA700B34460 /* StringPrototype.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C5250E16FCA700B34460 /* StringPrototype.lut.h */; }; BC18C52A0E16FCC200B34460 /* MathObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C5290E16FCC200B34460 /* MathObject.lut.h */; }; BC18C52C0E16FCD200B34460 /* RegExpObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C52B0E16FCD200B34460 /* RegExpObject.lut.h */; }; - BC18C52E0E16FCE100B34460 /* lexer.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C52D0E16FCE100B34460 /* lexer.lut.h */; }; - BC18C5300E16FCEB00B34460 /* grammar.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C52F0E16FCEB00B34460 /* grammar.h */; }; + BC18C52E0E16FCE100B34460 /* Lexer.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C52D0E16FCE100B34460 /* Lexer.lut.h */; }; + BC18C5300E16FCEB00B34460 /* Grammar.h in Headers */ = {isa = PBXBuildFile; fileRef = BC18C52F0E16FCEB00B34460 /* Grammar.h */; }; BC257DE80E1F51C50016B6C9 /* Arguments.h in Headers */ = {isa = PBXBuildFile; fileRef = BC257DE60E1F51C50016B6C9 /* Arguments.h */; }; BC257DF00E1F52ED0016B6C9 /* GlobalEvalFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = BC257DEE0E1F52ED0016B6C9 /* GlobalEvalFunction.h */; }; BC257DF40E1F53740016B6C9 /* PrototypeFunction.h in Headers */ = {isa = PBXBuildFile; fileRef = BC257DF20E1F53740016B6C9 /* PrototypeFunction.h */; settings = {ATTRIBUTES = (Private, ); }; }; @@ -362,6 +444,7 @@ BC6AAAE50E1F426500AD87D8 /* ClassInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BC6AAAE40E1F426500AD87D8 /* ClassInfo.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC756FC90E2031B200DE7D12 /* JSGlobalObjectFunctions.h in Headers */ = {isa = PBXBuildFile; fileRef = BC756FC70E2031B200DE7D12 /* JSGlobalObjectFunctions.h */; }; BC7F8FB90E19D1C3008632C0 /* JSNumberCell.h in Headers */ = {isa = PBXBuildFile; fileRef = BC7F8FB80E19D1C3008632C0 /* JSNumberCell.h */; settings = {ATTRIBUTES = (Private, ); }; }; + BC87CDB910712AD4000614CF /* JSONObject.lut.h in Headers */ = {isa = PBXBuildFile; fileRef = BC87CDB810712ACA000614CF /* JSONObject.lut.h */; }; BC9041480EB9250900FE26FA /* StructureTransitionTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BC9041470EB9250900FE26FA /* StructureTransitionTable.h */; settings = {ATTRIBUTES = (Private, ); }; }; BC95437D0EBA70FD0072B6D3 /* PropertyMapHashTable.h in Headers */ = {isa = PBXBuildFile; fileRef = BC95437C0EBA70FD0072B6D3 /* PropertyMapHashTable.h */; settings = {ATTRIBUTES = (Private, ); }; }; BCCF0D080EF0AAB900413C8F /* StructureStubInfo.h in Headers */ = {isa = PBXBuildFile; fileRef = BCCF0D070EF0AAB900413C8F /* StructureStubInfo.h */; }; @@ -481,6 +564,7 @@ 1412110D0A48788700480255 /* minidom.js */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.javascript; name = minidom.js; path = tests/minidom.js; sourceTree = "<group>"; }; 141211200A48793C00480255 /* minidom */ = {isa = PBXFileReference; explicitFileType = "compiled.mach-o.executable"; includeInIndex = 0; path = minidom; sourceTree = BUILT_PRODUCTS_DIR; }; 1419D32C0CEA7CDE00FF507A /* RefCounted.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefCounted.h; sourceTree = "<group>"; }; + 1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WeakRandom.h; sourceTree = "<group>"; }; 1421359A0A677F4F00A8195E /* JSBase.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSBase.cpp; sourceTree = "<group>"; }; 142711380A460BBB0080EEEA /* JSBase.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSBase.h; sourceTree = "<group>"; }; 1429D77B0ED20D7300B89619 /* Interpreter.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Interpreter.h; sourceTree = "<group>"; }; @@ -502,6 +586,7 @@ 1429DABE0ED263E700B89619 /* WRECParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WRECParser.cpp; sourceTree = "<group>"; }; 1429DADE0ED2645B00B89619 /* WRECGenerator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WRECGenerator.h; sourceTree = "<group>"; }; 1429DADF0ED2645B00B89619 /* WRECGenerator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = WRECGenerator.cpp; sourceTree = "<group>"; }; + 142D3938103E4560007DCB52 /* NumericStrings.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = NumericStrings.h; sourceTree = "<group>"; }; 1440051F0A531D3B0005F061 /* Node.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = Node.h; path = tests/Node.h; sourceTree = "<group>"; }; 144005200A531D3B0005F061 /* Node.c */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c; name = Node.c; path = tests/Node.c; sourceTree = "<group>"; }; 144007480A536CC20005F061 /* NodeList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = NodeList.h; path = tests/NodeList.h; sourceTree = "<group>"; }; @@ -532,8 +617,10 @@ 1483B589099BC1950016E4F0 /* JSImmediate.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = JSImmediate.h; sourceTree = "<group>"; }; 148A1626095D16BB00666D0D /* ListRefPtr.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ListRefPtr.h; sourceTree = "<group>"; }; 148A1ECD0D10C23B0069A47C /* RefPtrHashMap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RefPtrHashMap.h; sourceTree = "<group>"; }; + 148CD1D7108CF902008163C6 /* JSContextRefPrivate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSContextRefPrivate.h; sourceTree = "<group>"; }; 149559ED0DDCDDF700648087 /* DebuggerCallFrame.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = DebuggerCallFrame.cpp; sourceTree = "<group>"; }; 149B24FF0D8AF6D1009CB8C7 /* Register.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Register.h; sourceTree = "<group>"; }; + 14A1563010966365006FA260 /* DateInstanceCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DateInstanceCache.h; sourceTree = "<group>"; }; 14A23D6C0F4E19CE0023CDAD /* JITStubs.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITStubs.cpp; sourceTree = "<group>"; }; 14A396A60CD2933100B5B4FF /* SymbolTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SymbolTable.h; sourceTree = "<group>"; }; 14A42E3D0F4F60EE00599099 /* TimeoutChecker.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TimeoutChecker.cpp; sourceTree = "<group>"; }; @@ -584,7 +671,7 @@ 5DA479650CFBCF56009328A0 /* TCPackedCache.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TCPackedCache.h; sourceTree = "<group>"; }; 5DBD18AF0C5401A700C15EAE /* MallocZoneSupport.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MallocZoneSupport.h; sourceTree = "<group>"; }; 5DE3D0F40DD8DDFB00468714 /* WebKitAvailability.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = WebKitAvailability.h; sourceTree = "<group>"; }; - 6507D2970E871E4A00D7D896 /* TypeInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = TypeInfo.h; sourceTree = "<group>"; }; + 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSTypeInfo.h; sourceTree = "<group>"; }; 651F6412039D5B5F0078395C /* dtoa.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = dtoa.cpp; sourceTree = "<group>"; tabWidth = 8; }; 651F6413039D5B5F0078395C /* dtoa.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = dtoa.h; sourceTree = "<group>"; tabWidth = 8; }; 652246A40C8D7A0E007BDAF7 /* HashIterators.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = HashIterators.h; sourceTree = "<group>"; }; @@ -595,13 +682,13 @@ 6541BD6F08E80A17002CBEE7 /* TCSpinLock.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = TCSpinLock.h; sourceTree = "<group>"; tabWidth = 8; }; 6541BD7008E80A17002CBEE7 /* TCSystemAlloc.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = TCSystemAlloc.cpp; sourceTree = "<group>"; tabWidth = 8; }; 6541BD7108E80A17002CBEE7 /* TCSystemAlloc.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = TCSystemAlloc.h; sourceTree = "<group>"; tabWidth = 8; }; + 655EB29A10CE2581001A990E /* NodesCodegen.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = NodesCodegen.cpp; sourceTree = "<group>"; }; 6560A4CF04B3B3E7008AE952 /* CoreFoundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreFoundation.framework; path = /System/Library/Frameworks/CoreFoundation.framework; sourceTree = "<absolute>"; }; 65621E6B089E859700760F35 /* PropertySlot.cpp */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertySlot.cpp; sourceTree = "<group>"; tabWidth = 8; }; 65621E6C089E859700760F35 /* PropertySlot.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = PropertySlot.h; sourceTree = "<group>"; tabWidth = 8; }; 657EB7450B708F540063461B /* ListHashSet.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = ListHashSet.h; sourceTree = "<group>"; }; 657EEBBF094E445E008C9C7B /* HashCountedSet.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = HashCountedSet.h; sourceTree = "<group>"; tabWidth = 8; }; 6580F795094070560082C219 /* PassRefPtr.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = PassRefPtr.h; sourceTree = "<group>"; tabWidth = 8; }; - 659126BC0BDD1728001921FB /* AllInOneFile.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = AllInOneFile.cpp; sourceTree = "<group>"; }; 6592C316098B7DE10003D4F6 /* Vector.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = Vector.h; sourceTree = "<group>"; }; 6592C317098B7DE10003D4F6 /* VectorTraits.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = VectorTraits.h; sourceTree = "<group>"; }; 65B174BE09D1000200820339 /* chartables.c */ = {isa = PBXFileReference; explicitFileType = sourcecode.c.c; fileEncoding = 30; path = chartables.c; sourceTree = "<group>"; }; @@ -626,7 +713,7 @@ 65EA4C9A092AF9E20093D800 /* JSLock.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = JSLock.h; sourceTree = "<group>"; tabWidth = 8; }; 65EA73620BAE35D1001BB560 /* CommonIdentifiers.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = CommonIdentifiers.cpp; sourceTree = "<group>"; }; 65EA73630BAE35D1001BB560 /* CommonIdentifiers.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; path = CommonIdentifiers.h; sourceTree = "<group>"; }; - 65FB3F4809D11B2400F49DEB /* grammar.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = grammar.cpp; sourceTree = "<group>"; }; + 65FB3F4809D11B2400F49DEB /* Grammar.cpp */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.cpp.cpp; path = Grammar.cpp; sourceTree = "<group>"; }; 704FD35305697E6D003DBED9 /* BooleanObject.h */ = {isa = PBXFileReference; fileEncoding = 30; indentWidth = 4; lastKnownFileType = sourcecode.c.h; path = BooleanObject.h; sourceTree = "<group>"; tabWidth = 8; }; 7E2ADD8D0E79AAD500D50C51 /* CharacterClassConstructor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CharacterClassConstructor.h; sourceTree = "<group>"; }; 7E2ADD8F0E79AC1100D50C51 /* CharacterClassConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = CharacterClassConstructor.cpp; sourceTree = "<group>"; }; @@ -646,6 +733,8 @@ 86ADD1430FDDEA980006EEC2 /* ARMv7Assembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ARMv7Assembler.h; sourceTree = "<group>"; }; 86ADD1440FDDEA980006EEC2 /* MacroAssemblerARMv7.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssemblerARMv7.h; sourceTree = "<group>"; }; 86C36EE90EE1289D00B3DF59 /* MacroAssembler.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MacroAssembler.h; sourceTree = "<group>"; }; + 86CA032D1038E8440028A609 /* Executable.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Executable.cpp; sourceTree = "<group>"; }; + 86CAFEE21035DDE60028A609 /* Executable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Executable.h; sourceTree = "<group>"; }; 86CC85A00EE79A4700288682 /* JITInlineMethods.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JITInlineMethods.h; sourceTree = "<group>"; }; 86CC85A20EE79B7400288682 /* JITCall.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITCall.cpp; sourceTree = "<group>"; }; 86CC85C30EE7A89400288682 /* JITPropertyAccess.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JITPropertyAccess.cpp; sourceTree = "<group>"; }; @@ -751,7 +840,10 @@ A7A1F7AB0F252B3C00E184E2 /* ByteArray.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ByteArray.h; sourceTree = "<group>"; }; A7B48DB50EE74CFC00DCBDB6 /* ExecutableAllocator.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExecutableAllocator.h; sourceTree = "<group>"; }; A7B48DB60EE74CFC00DCBDB6 /* ExecutableAllocator.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ExecutableAllocator.cpp; sourceTree = "<group>"; }; + A7C2216810C745E000F97913 /* JSZombie.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSZombie.h; sourceTree = "<group>"; }; + A7C2216B10C7469C00F97913 /* JSZombie.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSZombie.cpp; sourceTree = "<group>"; }; A7C530E3102A3813005BC741 /* MarkStackPosix.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = MarkStackPosix.cpp; sourceTree = "<group>"; }; + A7D649A91015224E009B2E1B /* PossiblyNull.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PossiblyNull.h; sourceTree = "<group>"; }; A7E2EA690FB460CF00601F06 /* LiteralParser.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = LiteralParser.h; sourceTree = "<group>"; }; A7E2EA6A0FB460CF00601F06 /* LiteralParser.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = LiteralParser.cpp; sourceTree = "<group>"; }; A7E42C180E3938830065A544 /* JSStaticScopeObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSStaticScopeObject.h; sourceTree = "<group>"; }; @@ -760,7 +852,8 @@ A7F869EC0F95C2EC00558697 /* CallFrameClosure.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CallFrameClosure.h; sourceTree = "<group>"; }; A7F9935D0FD7325100A0B2D0 /* JSONObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONObject.h; sourceTree = "<group>"; }; A7F9935E0FD7325100A0B2D0 /* JSONObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSONObject.cpp; sourceTree = "<group>"; }; - A7F9949A0FD746A300A0B2D0 /* JSONObject.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = JSONObject.lut.h; path = /Users/oliver/builds/Debug/DerivedSources/JavaScriptCore/JSONObject.lut.h; sourceTree = "<absolute>"; }; + A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyDescriptor.h; sourceTree = "<group>"; }; + A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = PropertyDescriptor.cpp; sourceTree = "<group>"; }; A8E894310CD0602400367179 /* JSCallbackObjectFunctions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSCallbackObjectFunctions.h; sourceTree = "<group>"; }; A8E894330CD0603F00367179 /* JSGlobalObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSGlobalObject.h; sourceTree = "<group>"; }; BC02E9040E1839DB000F9297 /* ErrorConstructor.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = ErrorConstructor.cpp; sourceTree = "<group>"; }; @@ -793,8 +886,8 @@ BC18C5250E16FCA700B34460 /* StringPrototype.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StringPrototype.lut.h; sourceTree = "<group>"; }; BC18C5290E16FCC200B34460 /* MathObject.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = MathObject.lut.h; sourceTree = "<group>"; }; BC18C52B0E16FCD200B34460 /* RegExpObject.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RegExpObject.lut.h; sourceTree = "<group>"; }; - BC18C52D0E16FCE100B34460 /* lexer.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = lexer.lut.h; sourceTree = "<group>"; }; - BC18C52F0E16FCEB00B34460 /* grammar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = grammar.h; sourceTree = "<group>"; }; + BC18C52D0E16FCE100B34460 /* Lexer.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Lexer.lut.h; sourceTree = "<group>"; }; + BC18C52F0E16FCEB00B34460 /* Grammar.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = Grammar.h; sourceTree = "<group>"; }; BC22A3980E16E14800AF21C8 /* JSObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSObject.cpp; sourceTree = "<group>"; }; BC22A3990E16E14800AF21C8 /* JSObject.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSObject.h; sourceTree = "<group>"; }; BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSVariableObject.cpp; sourceTree = "<group>"; }; @@ -831,6 +924,7 @@ BC7952350E15EB5600A898AB /* BooleanPrototype.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BooleanPrototype.h; sourceTree = "<group>"; }; BC7F8FB80E19D1C3008632C0 /* JSNumberCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSNumberCell.h; sourceTree = "<group>"; }; BC7F8FBA0E19D1EF008632C0 /* JSCell.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSCell.cpp; sourceTree = "<group>"; }; + BC87CDB810712ACA000614CF /* JSONObject.lut.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JSONObject.lut.h; sourceTree = "<group>"; }; BC8F3CCF0DAF17BA00577A80 /* ConstructData.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ConstructData.h; sourceTree = "<group>"; }; BC9041470EB9250900FE26FA /* StructureTransitionTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StructureTransitionTable.h; sourceTree = "<group>"; }; BC95437C0EBA70FD0072B6D3 /* PropertyMapHashTable.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PropertyMapHashTable.h; sourceTree = "<group>"; }; @@ -989,7 +1083,6 @@ F692A8540255597D01FF60F7 /* create_hash_table */, 14B8ECA60A5653980062BE54 /* JavaScriptCore.exp */, F5C290E60284F98E018635CA /* JavaScriptCorePrefix.h */, - 659126BC0BDD1728001921FB /* AllInOneFile.cpp */, 45E12D8806A49B0F00E9DF84 /* jsc.cpp */, F68EBB8C0255D4C601FF60F7 /* config.h */, 1432EBD70A34CAD400717B9F /* API */, @@ -1103,6 +1196,7 @@ 1440FCE10A51E46B0005F061 /* JSClassRef.h */, 14BD5A290A3E91F600BAF59C /* JSContextRef.cpp */, 14BD5A2A0A3E91F600BAF59C /* JSContextRef.h */, + 148CD1D7108CF902008163C6 /* JSContextRefPrivate.h */, 1482B7E20A43076000517CFC /* JSObjectRef.cpp */, 1482B7E10A43076000517CFC /* JSObjectRef.h */, 95988BA90E477BEC00D28D4D /* JSProfilerPrivate.cpp */, @@ -1174,10 +1268,10 @@ BC18C5230E16FC8A00B34460 /* ArrayPrototype.lut.h */, 65B174BE09D1000200820339 /* chartables.c */, BCD203E70E1718F4002C7E82 /* DatePrototype.lut.h */, - 65FB3F4809D11B2400F49DEB /* grammar.cpp */, - BC18C52F0E16FCEB00B34460 /* grammar.h */, - A7F9949A0FD746A300A0B2D0 /* JSONObject.lut.h */, - BC18C52D0E16FCE100B34460 /* lexer.lut.h */, + 65FB3F4809D11B2400F49DEB /* Grammar.cpp */, + BC18C52F0E16FCEB00B34460 /* Grammar.h */, + BC87CDB810712ACA000614CF /* JSONObject.lut.h */, + BC18C52D0E16FCE100B34460 /* Lexer.lut.h */, BC18C5290E16FCC200B34460 /* MathObject.lut.h */, BC2680E60E16D52300A06E92 /* NumberConstructor.lut.h */, BCD202D50E170708002C7E82 /* RegExpConstructor.lut.h */, @@ -1242,6 +1336,7 @@ 44DD48520FAEA85000D6B4EB /* PassOwnPtr.h */, 6580F795094070560082C219 /* PassRefPtr.h */, 65D6D87E09B5A32E0002E4D7 /* Platform.h */, + A7D649A91015224E009B2E1B /* PossiblyNull.h */, 0B1F921B0F17502D0036468E /* PtrAndFlags.h */, 088FA5B90EF76D4300578E6F /* RandomNumber.cpp */, 088FA5BA0EF76D4300578E6F /* RandomNumber.h */, @@ -1297,6 +1392,7 @@ isa = PBXGroup; children = ( 969A07200ED1CE3300F1F681 /* BytecodeGenerator.cpp */, + 655EB29A10CE2581001A990E /* NodesCodegen.cpp */, 969A07210ED1CE3300F1F681 /* BytecodeGenerator.h */, 969A07270ED1CE6900F1F681 /* Label.h */, 960097A50EBABB58007A7297 /* LabelScope.h */, @@ -1363,6 +1459,7 @@ D21202290AD4310C00ED79B6 /* DateConversion.h */, BC1166000E1997B1008066DD /* DateInstance.cpp */, BC1166010E1997B1008066DD /* DateInstance.h */, + 14A1563010966365006FA260 /* DateInstanceCache.h */, BCD203470E17135E002C7E82 /* DatePrototype.cpp */, BCD203480E17135E002C7E82 /* DatePrototype.h */, BC337BEA0E1B00CB0076918A /* Error.cpp */, @@ -1375,6 +1472,8 @@ BC02E9070E1839DB000F9297 /* ErrorPrototype.h */, 1429D8770ED21ACD00B89619 /* ExceptionHelpers.cpp */, A72701B30DADE94900E548D7 /* ExceptionHelpers.h */, + 86CA032D1038E8440028A609 /* Executable.cpp */, + 86CAFEE21035DDE60028A609 /* Executable.h */, BC2680C00E16D4E900A06E92 /* FunctionConstructor.cpp */, BC2680C10E16D4E900A06E92 /* FunctionConstructor.h */, F692A85C0255597D01FF60F7 /* FunctionPrototype.cpp */, @@ -1424,6 +1523,7 @@ BC02E9B60E1842FA000F9297 /* JSString.cpp */, F692A8620255597D01FF60F7 /* JSString.h */, 14ABB454099C2A0F00E2A24F /* JSType.h */, + 6507D2970E871E4A00D7D896 /* JSTypeInfo.h */, F692A8870255597D01FF60F7 /* JSValue.cpp */, 14ABB36E099C076400E2A24F /* JSValue.h */, BC22A39A0E16E14800AF21C8 /* JSVariableObject.cpp */, @@ -1434,6 +1534,9 @@ A7E2EA690FB460CF00601F06 /* LiteralParser.h */, F692A8680255597D01FF60F7 /* Lookup.cpp */, F692A8690255597D01FF60F7 /* Lookup.h */, + A74B3498102A5F8E0032AB98 /* MarkStack.cpp */, + A779558F101A74D500114E55 /* MarkStack.h */, + A7C530E3102A3813005BC741 /* MarkStackPosix.cpp */, F692A86A0255597D01FF60F7 /* MathObject.cpp */, F692A86B0255597D01FF60F7 /* MathObject.h */, BC02E9080E1839DB000F9297 /* NativeErrorConstructor.cpp */, @@ -1447,12 +1550,15 @@ F692A8710255597D01FF60F7 /* NumberObject.h */, BC2680C40E16D4E900A06E92 /* NumberPrototype.cpp */, BC2680C50E16D4E900A06E92 /* NumberPrototype.h */, + 142D3938103E4560007DCB52 /* NumericStrings.h */, BC2680C60E16D4E900A06E92 /* ObjectConstructor.cpp */, BC2680C70E16D4E900A06E92 /* ObjectConstructor.h */, BC2680C80E16D4E900A06E92 /* ObjectPrototype.cpp */, BC2680C90E16D4E900A06E92 /* ObjectPrototype.h */, F692A8770255597D01FF60F7 /* Operations.cpp */, F692A8780255597D01FF60F7 /* Operations.h */, + A7FB60A3103F7DC20017A286 /* PropertyDescriptor.cpp */, + A7FB604B103F5EAB0017A286 /* PropertyDescriptor.h */, BC95437C0EBA70FD0072B6D3 /* PropertyMapHashTable.h */, 65400C0F0A69BAF200509887 /* PropertyNameArray.cpp */, 65400C100A69BAF200509887 /* PropertyNameArray.h */, @@ -1493,12 +1599,11 @@ 14A42E3E0F4F60EE00599099 /* TimeoutChecker.h */, 5D53726D0E1C546B0021E549 /* Tracing.d */, 5D53726E0E1C54880021E549 /* Tracing.h */, - 6507D2970E871E4A00D7D896 /* TypeInfo.h */, F692A8850255597D01FF60F7 /* UString.cpp */, F692A8860255597D01FF60F7 /* UString.h */, - A779558F101A74D500114E55 /* MarkStack.h */, - A7C530E3102A3813005BC741 /* MarkStackPosix.cpp */, - A74B3498102A5F8E0032AB98 /* MarkStack.cpp */, + 1420BE7A10AA6DDB00F455D2 /* WeakRandom.h */, + A7C2216810C745E000F97913 /* JSZombie.h */, + A7C2216B10C7469C00F97913 /* JSZombie.cpp */, ); path = runtime; sourceTree = "<group>"; @@ -1716,7 +1821,7 @@ BC18C4050E16F5CD00B34460 /* FunctionPrototype.h in Headers */, BC18C4060E16F5CD00B34460 /* GetPtr.h in Headers */, BC257DF00E1F52ED0016B6C9 /* GlobalEvalFunction.h in Headers */, - BC18C5300E16FCEB00B34460 /* grammar.h in Headers */, + BC18C5300E16FCEB00B34460 /* Grammar.h in Headers */, BC18C4080E16F5CD00B34460 /* HashCountedSet.h in Headers */, BC18C4090E16F5CD00B34460 /* HashFunctions.h in Headers */, BC18C40A0E16F5CD00B34460 /* HashIterators.h in Headers */, @@ -1760,7 +1865,6 @@ BC18C4240E16F5CD00B34460 /* JSObject.h in Headers */, BC18C4250E16F5CD00B34460 /* JSObjectRef.h in Headers */, A7F9935F0FD7325100A0B2D0 /* JSONObject.h in Headers */, - A7F9949B0FD746A300A0B2D0 /* JSONObject.lut.h in Headers */, 9534AAFB0E5B7A9600B8A45B /* JSProfilerPrivate.h in Headers */, BC18C4260E16F5CD00B34460 /* JSRetainPtr.h in Headers */, BC18C4270E16F5CD00B34460 /* JSString.h in Headers */, @@ -1775,7 +1879,7 @@ 969A072A0ED1CE6900F1F681 /* Label.h in Headers */, 960097A60EBABB58007A7297 /* LabelScope.h in Headers */, BC18C4310E16F5CD00B34460 /* Lexer.h in Headers */, - BC18C52E0E16FCE100B34460 /* lexer.lut.h in Headers */, + BC18C52E0E16FCE100B34460 /* Lexer.lut.h in Headers */, 86D3B3C310159D7F002865E7 /* LinkBuffer.h in Headers */, BC18C4340E16F5CD00B34460 /* ListHashSet.h in Headers */, BC18C4350E16F5CD00B34460 /* ListRefPtr.h in Headers */, @@ -1884,7 +1988,7 @@ BC18C4710E16F5CD00B34460 /* ThreadSpecific.h in Headers */, 14A42E400F4F60EE00599099 /* TimeoutChecker.h in Headers */, 5D53726F0E1C54880021E549 /* Tracing.h in Headers */, - 6507D29E0E871E5E00D7D896 /* TypeInfo.h in Headers */, + 6507D29E0E871E5E00D7D896 /* JSTypeInfo.h in Headers */, 0B4D7E630F319AC800AD7E58 /* TypeTraits.h in Headers */, BC18C4720E16F5CD00B34460 /* ucpinternal.h in Headers */, BC18C4730E16F5CD00B34460 /* Unicode.h in Headers */, @@ -1902,6 +2006,14 @@ 1429DABF0ED263E700B89619 /* WRECParser.h in Headers */, 9688CB160ED12B4E001D649F /* X86Assembler.h in Headers */, A7795590101A74D500114E55 /* MarkStack.h in Headers */, + A7D649AA1015224E009B2E1B /* PossiblyNull.h in Headers */, + 86CAFEE31035DDE60028A609 /* Executable.h in Headers */, + 142D3939103E4560007DCB52 /* NumericStrings.h in Headers */, + A7FB61001040C38B0017A286 /* PropertyDescriptor.h in Headers */, + BC87CDB910712AD4000614CF /* JSONObject.lut.h in Headers */, + 148CD1D8108CF902008163C6 /* JSContextRefPrivate.h in Headers */, + 14A1563210966365006FA260 /* DateInstanceCache.h in Headers */, + 1420BE7B10AA6DDB00F455D2 /* WeakRandom.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -2084,7 +2196,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = "# Touch Info.plist to let Xcode know it needs to copy it into the built product\ntouch \"$SRCROOT/Info.plist\"\n"; + shellScript = "# Touch Info.plist to let Xcode know it needs to copy it into the built product\nif [[ \"${CONFIGURATION}\" != \"Production\" ]]; then\n touch \"$SRCROOT/Info.plist\";\nfi;\n"; }; 5D35DEE10C7C140B008648B2 /* Generate DTrace header */ = { isa = PBXShellScriptBuildPhase; @@ -2188,26 +2300,57 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( - 659126BD0BDD1728001921FB /* AllInOneFile.cpp in Sources */, + 147F39BD107EC37600427A48 /* ArgList.cpp in Sources */, + 147F39BE107EC37600427A48 /* Arguments.cpp in Sources */, 86D3B2C310156BDE002865E7 /* ARMAssembler.cpp in Sources */, + 147F39BF107EC37600427A48 /* ArrayConstructor.cpp in Sources */, + 147F39C0107EC37600427A48 /* ArrayPrototype.cpp in Sources */, 65FDE49C0BDD1D4A00E80111 /* Assertions.cpp in Sources */, + 14280863107EC11A0013E7B2 /* BooleanConstructor.cpp in Sources */, + 14280864107EC11A0013E7B2 /* BooleanObject.cpp in Sources */, + 14280865107EC11A0013E7B2 /* BooleanPrototype.cpp in Sources */, A7A1F7AC0F252B3C00E184E2 /* ByteArray.cpp in Sources */, + 148F21AA107EC53A0042EC2C /* BytecodeGenerator.cpp in Sources */, + 1428082D107EC0570013E7B2 /* CallData.cpp in Sources */, 1429D8DD0ED2205B00B89619 /* CallFrame.cpp in Sources */, 1429D9C40ED23C3900B89619 /* CharacterClass.cpp in Sources */, 7E2ADD900E79AC1100D50C51 /* CharacterClassConstructor.cpp in Sources */, 969A07960ED1D3AE00F1F681 /* CodeBlock.cpp in Sources */, E1A862D60D7F2B5C001EC6AA /* CollatorDefault.cpp in Sources */, E1A862A90D7EBB76001EC6AA /* CollatorICU.cpp in Sources */, + 14F8BA4F107EC899009892DC /* Collector.cpp in Sources */, + 147F39C1107EC37600427A48 /* CommonIdentifiers.cpp in Sources */, + 147F39C2107EC37600427A48 /* Completion.cpp in Sources */, + 1428082E107EC0570013E7B2 /* ConstructData.cpp in Sources */, 180B9BFE0F16E94D009BDBC5 /* CurrentTime.cpp in Sources */, + 147F39C3107EC37600427A48 /* DateConstructor.cpp in Sources */, + 147F39C4107EC37600427A48 /* DateConversion.cpp in Sources */, + 147F39C5107EC37600427A48 /* DateInstance.cpp in Sources */, 41359CF60FDD89CB00206180 /* DateMath.cpp in Sources */, + 147F39C6107EC37600427A48 /* DatePrototype.cpp in Sources */, + 14280823107EC02C0013E7B2 /* Debugger.cpp in Sources */, BC3135650F302FA3003DFD3A /* DebuggerActivation.cpp in Sources */, 149559EE0DDCDDF700648087 /* DebuggerCallFrame.cpp in Sources */, + 14469DD7107EC79E00650446 /* dtoa.cpp in Sources */, + 147F39C7107EC37600427A48 /* Error.cpp in Sources */, + 147F39C8107EC37600427A48 /* ErrorConstructor.cpp in Sources */, + 147F39C9107EC37600427A48 /* ErrorInstance.cpp in Sources */, + 147F39CA107EC37600427A48 /* ErrorPrototype.cpp in Sources */, 1429D8780ED21ACD00B89619 /* ExceptionHelpers.cpp in Sources */, + 86CA032E1038E8440028A609 /* Executable.cpp in Sources */, A7B48F490EE8936F00DCBDB6 /* ExecutableAllocator.cpp in Sources */, 86DB64640F95C6FC00D7D921 /* ExecutableAllocatorFixedVMPool.cpp in Sources */, A782F1A50EEC9FA20036273F /* ExecutableAllocatorPosix.cpp in Sources */, + 14F8BA3E107EC886009892DC /* FastMalloc.cpp in Sources */, + 147F39CB107EC37600427A48 /* FunctionConstructor.cpp in Sources */, + 147F39CC107EC37600427A48 /* FunctionPrototype.cpp in Sources */, + 14280855107EC0E70013E7B2 /* GetterSetter.cpp in Sources */, + 147F39CD107EC37600427A48 /* GlobalEvalFunction.cpp in Sources */, + 148F21A3107EC5310042EC2C /* Grammar.cpp in Sources */, 65DFC93308EA173A00F7300B /* HashTable.cpp in Sources */, + 147F39CE107EC37600427A48 /* Identifier.cpp in Sources */, E178636D0D9BEEC300D74E75 /* InitializeThreading.cpp in Sources */, + 147F39CF107EC37600427A48 /* InternalFunction.cpp in Sources */, 1429D7D40ED2128200B89619 /* Interpreter.cpp in Sources */, 1429D92F0ED22D7000B89619 /* JIT.cpp in Sources */, 86A90ED00EE7D51F00AB350D /* JITArithmetic.cpp in Sources */, @@ -2216,28 +2359,58 @@ 86CC85C40EE7A89400288682 /* JITPropertyAccess.cpp in Sources */, 14A23D750F4E1ABB0023CDAD /* JITStubs.cpp in Sources */, 140B7D1D0DC69AF7009C42B8 /* JSActivation.cpp in Sources */, + 140566C4107EC255005DBC8D /* JSAPIValueWrapper.cpp in Sources */, + 147F39D0107EC37600427A48 /* JSArray.cpp in Sources */, 1421359B0A677F4F00A8195E /* JSBase.cpp in Sources */, A791EF290F11E07900AE1F68 /* JSByteArray.cpp in Sources */, 1440F8AF0A508D200005F061 /* JSCallbackConstructor.cpp in Sources */, 1440F8920A508B100005F061 /* JSCallbackFunction.cpp in Sources */, 14ABDF600A437FEF00ECCA01 /* JSCallbackObject.cpp in Sources */, + 147F39D1107EC37600427A48 /* JSCell.cpp in Sources */, 1440FCE40A51E46B0005F061 /* JSClassRef.cpp in Sources */, 14BD5A300A3E91F600BAF59C /* JSContextRef.cpp in Sources */, + 140566D6107EC271005DBC8D /* JSFunction.cpp in Sources */, E18E3A590DF9278C00D90B34 /* JSGlobalData.cpp in Sources */, + 147F39D2107EC37600427A48 /* JSGlobalObject.cpp in Sources */, + 14E9D17B107EC469004DDA21 /* JSGlobalObjectFunctions.cpp in Sources */, + 147F39D3107EC37600427A48 /* JSImmediate.cpp in Sources */, + 14280875107EC13E0013E7B2 /* JSLock.cpp in Sources */, A72700900DAC6BBC00E548D7 /* JSNotAnObject.cpp in Sources */, + 1428085D107EC0F80013E7B2 /* JSNumberCell.cpp in Sources */, + 147F39D4107EC37600427A48 /* JSObject.cpp in Sources */, 1482B7E40A43076000517CFC /* JSObjectRef.cpp in Sources */, A7F993600FD7325100A0B2D0 /* JSONObject.cpp in Sources */, 95F6E6950E5B5F970091E860 /* JSProfilerPrivate.cpp in Sources */, A727FF6B0DA3092200E548D7 /* JSPropertyNameIterator.cpp in Sources */, + 140566D1107EC267005DBC8D /* JSStaticScopeObject.cpp in Sources */, + 147F39D5107EC37600427A48 /* JSString.cpp in Sources */, 1482B74E0A43032800517CFC /* JSStringRef.cpp in Sources */, 146AAB380B66A94400E55F16 /* JSStringRefCF.cpp in Sources */, + 147F39D6107EC37600427A48 /* JSValue.cpp in Sources */, 14BD5A320A3E91F600BAF59C /* JSValueRef.cpp in Sources */, + 147F39D7107EC37600427A48 /* JSVariableObject.cpp in Sources */, + 14280870107EC1340013E7B2 /* JSWrapperObject.cpp in Sources */, BCFD8C920EEB2EE700283848 /* JumpTable.cpp in Sources */, + 148F21B0107EC5410042EC2C /* Lexer.cpp in Sources */, A7E2EA6C0FB460CF00601F06 /* LiteralParser.cpp in Sources */, + 14469DDE107EC7E700650446 /* Lookup.cpp in Sources */, 06D358B30DAADAA4003B174E /* MainThread.cpp in Sources */, 06D358B40DAADAAA003B174E /* MainThreadMac.mm in Sources */, + A74B3499102A5F8E0032AB98 /* MarkStack.cpp in Sources */, + A7C530E4102A3813005BC741 /* MarkStackPosix.cpp in Sources */, + 14469DDF107EC7E700650446 /* MathObject.cpp in Sources */, + 14469DE0107EC7E700650446 /* NativeErrorConstructor.cpp in Sources */, + 14469DE1107EC7E700650446 /* NativeErrorPrototype.cpp in Sources */, + 148F21B7107EC5470042EC2C /* Nodes.cpp in Sources */, + 14469DE2107EC7E700650446 /* NumberConstructor.cpp in Sources */, + 14469DE3107EC7E700650446 /* NumberObject.cpp in Sources */, + 14469DE4107EC7E700650446 /* NumberPrototype.cpp in Sources */, + 14469DE5107EC7E700650446 /* ObjectConstructor.cpp in Sources */, + 14469DE6107EC7E700650446 /* ObjectPrototype.cpp in Sources */, E124A8F80E555775003091F1 /* OpaqueJSString.cpp in Sources */, 969A079A0ED1D3AE00F1F681 /* Opcode.cpp in Sources */, + 14280850107EC0D70013E7B2 /* Operations.cpp in Sources */, + 148F21BC107EC54D0042EC2C /* Parser.cpp in Sources */, 93052C340FB792190048FDC3 /* ParserArena.cpp in Sources */, 930754C108B0F68000AB3056 /* pcre_compile.cpp in Sources */, 930754EB08B0F78500AB3056 /* pcre_exec.cpp in Sources */, @@ -2249,27 +2422,42 @@ 95AB83560DA43C3000BC83F3 /* ProfileNode.cpp in Sources */, 95AB83420DA4322500BC83F3 /* Profiler.cpp in Sources */, 1C61516C0EBAC7A00031376F /* ProfilerServer.mm in Sources */, + A7FB60A4103F7DC20017A286 /* PropertyDescriptor.cpp in Sources */, + 14469DE7107EC7E700650446 /* PropertyNameArray.cpp in Sources */, + 14469DE8107EC7E700650446 /* PropertySlot.cpp in Sources */, + 14469DE9107EC7E700650446 /* PrototypeFunction.cpp in Sources */, 088FA5BB0EF76D4300578E6F /* RandomNumber.cpp in Sources */, 905B02AE0E28640F006DF882 /* RefCountedLeakCounter.cpp in Sources */, 86EAC4950F93E8D1008EC948 /* RegexCompiler.cpp in Sources */, 86EAC4970F93E8D1008EC948 /* RegexInterpreter.cpp in Sources */, 86EAC4990F93E8D1008EC948 /* RegexJIT.cpp in Sources */, + 14280841107EC0930013E7B2 /* RegExp.cpp in Sources */, + 14280842107EC0930013E7B2 /* RegExpConstructor.cpp in Sources */, + 14280843107EC0930013E7B2 /* RegExpObject.cpp in Sources */, + 14280844107EC0930013E7B2 /* RegExpPrototype.cpp in Sources */, + 1428083A107EC0750013E7B2 /* RegisterFile.cpp in Sources */, 1429D8850ED21C3D00B89619 /* SamplingTool.cpp in Sources */, + 14469DEA107EC7E700650446 /* ScopeChain.cpp in Sources */, 9330402C0E6A764000786E6A /* SmallStrings.cpp in Sources */, + 14469DEB107EC7E700650446 /* StringConstructor.cpp in Sources */, + 14469DEC107EC7E700650446 /* StringObject.cpp in Sources */, + 14469DED107EC7E700650446 /* StringPrototype.cpp in Sources */, BCDE3B430E6C832D001453A7 /* Structure.cpp in Sources */, 7E4EE70F0EBB7A5B005934AA /* StructureChain.cpp in Sources */, BCCF0D0C0EF0B8A500413C8F /* StructureStubInfo.cpp in Sources */, + 14F8BA43107EC88C009892DC /* TCSystemAlloc.cpp in Sources */, 5D6A566B0F05995500266145 /* Threading.cpp in Sources */, E1EE793D0D6C9B9200FEA3BA /* ThreadingPthreads.cpp in Sources */, 14A42E3F0F4F60EE00599099 /* TimeoutChecker.cpp in Sources */, 0B330C270F38C62300692DE3 /* TypeTraits.cpp in Sources */, + 14469DEE107EC7E700650446 /* UString.cpp in Sources */, E1EF79AA0CE97BA60088D500 /* UTF8.cpp in Sources */, 869083150E6518D7000D36ED /* WREC.cpp in Sources */, 1429DA820ED2482900B89619 /* WRECFunctors.cpp in Sources */, 1429DAE10ED2645B00B89619 /* WRECGenerator.cpp in Sources */, 1429DAC00ED263E700B89619 /* WRECParser.cpp in Sources */, - A7C530E4102A3813005BC741 /* MarkStackPosix.cpp in Sources */, - A74B3499102A5F8E0032AB98 /* MarkStack.cpp in Sources */, + A7C2217810C7479400F97913 /* JSZombie.cpp in Sources */, + 655EB29B10CE2581001A990E /* NodesCodegen.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/JavaScriptCore/JavaScriptCoreSources.bkl b/JavaScriptCore/JavaScriptCoreSources.bkl index 1bdf251..1f36c1c 100644 --- a/JavaScriptCore/JavaScriptCoreSources.bkl +++ b/JavaScriptCore/JavaScriptCoreSources.bkl @@ -43,6 +43,7 @@ Source files for JSCore. </set> <set append="1" var="JSCORE_BYTECOMPILER_SOURCES"> bytecompiler/BytecodeGenerator.cpp + bytecompiler/NodesCodegen.cpp </set> <set append="1" var="JSCORE_DEBUGGER_SOURCES"> debugger/Debugger.cpp @@ -89,6 +90,7 @@ Source files for JSCore. runtime/DateConstructor.cpp runtime/DateConversion.cpp runtime/DateInstance.cpp + wtf/DateMath.cpp runtime/DatePrototype.cpp runtime/Error.cpp runtime/ErrorConstructor.cpp @@ -134,6 +136,7 @@ Source files for JSCore. runtime/ObjectConstructor.cpp runtime/ObjectPrototype.cpp runtime/Operations.cpp + runtime/PropertyDescriptor.cpp runtime/PropertyNameArray.cpp runtime/PropertySlot.cpp runtime/PrototypeFunction.cpp @@ -172,7 +175,6 @@ Source files for JSCore. wtf/Assertions.cpp wtf/ByteArray.cpp wtf/CurrentTime.cpp - wtf/DateMath.cpp wtf/FastMalloc.cpp wtf/HashTable.cpp wtf/MainThread.cpp diff --git a/JavaScriptCore/assembler/ARMAssembler.cpp b/JavaScriptCore/assembler/ARMAssembler.cpp index 69daa16..81c3222 100644 --- a/JavaScriptCore/assembler/ARMAssembler.cpp +++ b/JavaScriptCore/assembler/ARMAssembler.cpp @@ -26,7 +26,7 @@ #include "config.h" -#if ENABLE(ASSEMBLER) && PLATFORM(ARM) +#if ENABLE(ASSEMBLER) && PLATFORM(ARM_TRADITIONAL) #include "ARMAssembler.h" @@ -49,11 +49,11 @@ ARMWord* ARMAssembler::getLdrImmAddress(ARMWord* insn, uint32_t* constPool) return reinterpret_cast<ARMWord*>(addr - (*insn & SDT_OFFSET_MASK)); } -void ARMAssembler::linkBranch(void* code, JmpSrc from, void* to) +void ARMAssembler::linkBranch(void* code, JmpSrc from, void* to, int useConstantPool) { ARMWord* insn = reinterpret_cast<ARMWord*>(code) + (from.m_offset / sizeof(ARMWord)); - if (!from.m_latePatch) { + if (!useConstantPool) { int diff = reinterpret_cast<ARMWord*>(to) - reinterpret_cast<ARMWord*>(insn + 2); if ((diff <= BOFFSET_MAX && diff >= BOFFSET_MIN)) { @@ -118,7 +118,7 @@ ARMWord ARMAssembler::getOp2(ARMWord imm) if ((imm & 0x00ffffff) == 0) return OP2_IMM | (imm >> 24) | (rol << 8); - return 0; + return INVALID_IMM; } int ARMAssembler::genInt(int reg, ARMWord imm, bool positive) @@ -236,25 +236,18 @@ ARMWord ARMAssembler::getImm(ARMWord imm, int tmpReg, bool invert) // Do it by 1 instruction tmp = getOp2(imm); - if (tmp) + if (tmp != INVALID_IMM) return tmp; tmp = getOp2(~imm); - if (tmp) { + if (tmp != INVALID_IMM) { if (invert) return tmp | OP2_INV_IMM; mvn_r(tmpReg, tmp); return tmpReg; } - // Do it by 2 instruction - if (genInt(tmpReg, imm, true)) - return tmpReg; - if (genInt(tmpReg, ~imm, false)) - return tmpReg; - - ldr_imm(tmpReg, imm); - return tmpReg; + return encodeComplexImm(imm, tmpReg); } void ARMAssembler::moveImm(ARMWord imm, int dest) @@ -263,24 +256,43 @@ void ARMAssembler::moveImm(ARMWord imm, int dest) // Do it by 1 instruction tmp = getOp2(imm); - if (tmp) { + if (tmp != INVALID_IMM) { mov_r(dest, tmp); return; } tmp = getOp2(~imm); - if (tmp) { + if (tmp != INVALID_IMM) { mvn_r(dest, tmp); return; } + encodeComplexImm(imm, dest); +} + +ARMWord ARMAssembler::encodeComplexImm(ARMWord imm, int dest) +{ + ARMWord tmp; + +#if ARM_ARCH_VERSION >= 7 + tmp = getImm16Op2(imm); + if (tmp != INVALID_IMM) { + movw_r(dest, tmp); + return dest; + } + movw_r(dest, getImm16Op2(imm & 0xffff)); + movt_r(dest, getImm16Op2(imm >> 16)); + return dest; +#else // Do it by 2 instruction if (genInt(dest, imm, true)) - return; + return dest; if (genInt(dest, ~imm, false)) - return; + return dest; ldr_imm(dest, imm); + return dest; +#endif } // Memory load/store helpers @@ -291,10 +303,10 @@ void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID bas if (offset <= 0xfff) dtr_u(isLoad, srcDst, base, offset); else if (offset <= 0xfffff) { - add_r(ARM::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); - dtr_u(isLoad, srcDst, ARM::S0, offset & 0xfff); + add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); + dtr_u(isLoad, srcDst, ARMRegisters::S0, offset & 0xfff); } else { - ARMWord reg = getImm(offset, ARM::S0); + ARMWord reg = getImm(offset, ARMRegisters::S0); dtr_ur(isLoad, srcDst, base, reg); } } else { @@ -302,10 +314,10 @@ void ARMAssembler::dataTransfer32(bool isLoad, RegisterID srcDst, RegisterID bas if (offset <= 0xfff) dtr_d(isLoad, srcDst, base, offset); else if (offset <= 0xfffff) { - sub_r(ARM::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); - dtr_d(isLoad, srcDst, ARM::S0, offset & 0xfff); + sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 12) | (10 << 8)); + dtr_d(isLoad, srcDst, ARMRegisters::S0, offset & 0xfff); } else { - ARMWord reg = getImm(offset, ARM::S0); + ARMWord reg = getImm(offset, ARMRegisters::S0); dtr_dr(isLoad, srcDst, base, reg); } } @@ -319,19 +331,19 @@ void ARMAssembler::baseIndexTransfer32(bool isLoad, RegisterID srcDst, RegisterI op2 = lsl(index, scale); if (offset >= 0 && offset <= 0xfff) { - add_r(ARM::S0, base, op2); - dtr_u(isLoad, srcDst, ARM::S0, offset); + add_r(ARMRegisters::S0, base, op2); + dtr_u(isLoad, srcDst, ARMRegisters::S0, offset); return; } if (offset <= 0 && offset >= -0xfff) { - add_r(ARM::S0, base, op2); - dtr_d(isLoad, srcDst, ARM::S0, -offset); + add_r(ARMRegisters::S0, base, op2); + dtr_d(isLoad, srcDst, ARMRegisters::S0, -offset); return; } - ldr_un_imm(ARM::S0, offset); - add_r(ARM::S0, ARM::S0, op2); - dtr_ur(isLoad, srcDst, base, ARM::S0); + ldr_un_imm(ARMRegisters::S0, offset); + add_r(ARMRegisters::S0, ARMRegisters::S0, op2); + dtr_ur(isLoad, srcDst, base, ARMRegisters::S0); } void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID base, int32_t offset) @@ -342,8 +354,8 @@ void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID b return; } if (offset <= 0x3ffff && offset >= 0) { - add_r(ARM::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); - fdtr_u(isLoad, srcDst, ARM::S0, (offset >> 2) & 0xff); + add_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); + fdtr_u(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); return; } offset = -offset; @@ -353,27 +365,36 @@ void ARMAssembler::doubleTransfer(bool isLoad, FPRegisterID srcDst, RegisterID b return; } if (offset <= 0x3ffff && offset >= 0) { - sub_r(ARM::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); - fdtr_d(isLoad, srcDst, ARM::S0, (offset >> 2) & 0xff); + sub_r(ARMRegisters::S0, base, OP2_IMM | (offset >> 10) | (11 << 8)); + fdtr_d(isLoad, srcDst, ARMRegisters::S0, (offset >> 2) & 0xff); return; } offset = -offset; } - ldr_un_imm(ARM::S0, offset); - add_r(ARM::S0, ARM::S0, base); - fdtr_u(isLoad, srcDst, ARM::S0, 0); + ldr_un_imm(ARMRegisters::S0, offset); + add_r(ARMRegisters::S0, ARMRegisters::S0, base); + fdtr_u(isLoad, srcDst, ARMRegisters::S0, 0); } void* ARMAssembler::executableCopy(ExecutablePool* allocator) { + // 64-bit alignment is required for next constant pool and JIT code as well + m_buffer.flushWithoutBarrier(true); + if (m_buffer.uncheckedSize() & 0x7) + bkpt(0); + char* data = reinterpret_cast<char*>(m_buffer.executableCopy(allocator)); for (Jumps::Iterator iter = m_jumps.begin(); iter != m_jumps.end(); ++iter) { - ARMWord* ldrAddr = reinterpret_cast<ARMWord*>(data + *iter); - ARMWord* offset = getLdrImmAddress(ldrAddr); - if (*offset != 0xffffffff) - linkBranch(data, JmpSrc(*iter), data + *offset); + // The last bit is set if the constant must be placed on constant pool. + int pos = (*iter) & (~0x1); + ARMWord* ldrAddr = reinterpret_cast<ARMWord*>(data + pos); + ARMWord offset = *getLdrImmAddress(ldrAddr); + if (offset != 0xffffffff) { + JmpSrc jmpSrc(pos); + linkBranch(data, jmpSrc, data + offset, ((*iter) & 1)); + } } return data; @@ -381,4 +402,4 @@ void* ARMAssembler::executableCopy(ExecutablePool* allocator) } // namespace JSC -#endif // ENABLE(ASSEMBLER) && PLATFORM(ARM) +#endif // ENABLE(ASSEMBLER) && PLATFORM(ARM_TRADITIONAL) diff --git a/JavaScriptCore/assembler/ARMAssembler.h b/JavaScriptCore/assembler/ARMAssembler.h index d3fe782..712473e 100644 --- a/JavaScriptCore/assembler/ARMAssembler.h +++ b/JavaScriptCore/assembler/ARMAssembler.h @@ -29,55 +29,55 @@ #include <wtf/Platform.h> -#if ENABLE(ASSEMBLER) && PLATFORM(ARM) +#if ENABLE(ASSEMBLER) && PLATFORM(ARM_TRADITIONAL) #include "AssemblerBufferWithConstantPool.h" #include <wtf/Assertions.h> namespace JSC { -typedef uint32_t ARMWord; - -namespace ARM { - typedef enum { - r0 = 0, - r1, - r2, - r3, - S0 = r3, - r4, - r5, - r6, - r7, - r8, - S1 = r8, - r9, - r10, - r11, - r12, - r13, - sp = r13, - r14, - lr = r14, - r15, - pc = r15 - } RegisterID; - - typedef enum { - d0, - d1, - d2, - d3, - SD0 = d3 - } FPRegisterID; - -} // namespace ARM + typedef uint32_t ARMWord; + + namespace ARMRegisters { + typedef enum { + r0 = 0, + r1, + r2, + r3, + S0 = r3, + r4, + r5, + r6, + r7, + r8, + S1 = r8, + r9, + r10, + r11, + r12, + r13, + sp = r13, + r14, + lr = r14, + r15, + pc = r15 + } RegisterID; + + typedef enum { + d0, + d1, + d2, + d3, + SD0 = d3 + } FPRegisterID; + + } // namespace ARMRegisters class ARMAssembler { public: - typedef ARM::RegisterID RegisterID; - typedef ARM::FPRegisterID FPRegisterID; + typedef ARMRegisters::RegisterID RegisterID; + typedef ARMRegisters::FPRegisterID FPRegisterID; typedef AssemblerBufferWithConstantPool<2048, 4, 4, ARMAssembler> ARMBuffer; - typedef WTF::SegmentedVector<int, 64> Jumps; + typedef SegmentedVector<int, 64> Jumps; ARMAssembler() { } @@ -121,6 +121,7 @@ namespace ARM { MUL = 0x00000090, MULL = 0x00c00090, FADDD = 0x0e300b00, + FDIVD = 0x0e800b00, FSUBD = 0x0e300b40, FMULD = 0x0e200b00, FCMPD = 0x0eb40b40, @@ -133,12 +134,18 @@ namespace ARM { B = 0x0a000000, BL = 0x0b000000, FMSR = 0x0e000a10, + FMRS = 0x0e100a10, FSITOD = 0x0eb80bc0, + FTOSID = 0x0ebd0b40, FMSTAT = 0x0ef1fa10, #if ARM_ARCH_VERSION >= 5 CLZ = 0x016f0f10, BKPT = 0xe120070, #endif +#if ARM_ARCH_VERSION >= 7 + MOVW = 0x03000000, + MOVT = 0x03400000, +#endif }; enum { @@ -175,25 +182,23 @@ namespace ARM { padForAlign32 = 0xee120070, }; + static const ARMWord INVALID_IMM = 0xf0000000; + class JmpSrc { friend class ARMAssembler; public: JmpSrc() : m_offset(-1) - , m_latePatch(false) { } - void enableLatePatch() { m_latePatch = true; } private: JmpSrc(int offset) : m_offset(offset) - , m_latePatch(false) { } - int m_offset : 31; - int m_latePatch : 1; + int m_offset; }; class JmpDst { @@ -334,12 +339,26 @@ namespace ARM { void mov_r(int rd, ARMWord op2, Condition cc = AL) { - emitInst(static_cast<ARMWord>(cc) | MOV, rd, ARM::r0, op2); + emitInst(static_cast<ARMWord>(cc) | MOV, rd, ARMRegisters::r0, op2); } +#if ARM_ARCH_VERSION >= 7 + void movw_r(int rd, ARMWord op2, Condition cc = AL) + { + ASSERT((op2 | 0xf0fff) == 0xf0fff); + m_buffer.putInt(static_cast<ARMWord>(cc) | MOVW | RD(rd) | op2); + } + + void movt_r(int rd, ARMWord op2, Condition cc = AL) + { + ASSERT((op2 | 0xf0fff) == 0xf0fff); + m_buffer.putInt(static_cast<ARMWord>(cc) | MOVT | RD(rd) | op2); + } +#endif + void movs_r(int rd, ARMWord op2, Condition cc = AL) { - emitInst(static_cast<ARMWord>(cc) | MOV | SET_CC, rd, ARM::r0, op2); + emitInst(static_cast<ARMWord>(cc) | MOV | SET_CC, rd, ARMRegisters::r0, op2); } void bic_r(int rd, int rn, ARMWord op2, Condition cc = AL) @@ -354,12 +373,12 @@ namespace ARM { void mvn_r(int rd, ARMWord op2, Condition cc = AL) { - emitInst(static_cast<ARMWord>(cc) | MVN, rd, ARM::r0, op2); + emitInst(static_cast<ARMWord>(cc) | MVN, rd, ARMRegisters::r0, op2); } void mvns_r(int rd, ARMWord op2, Condition cc = AL) { - emitInst(static_cast<ARMWord>(cc) | MVN | SET_CC, rd, ARM::r0, op2); + emitInst(static_cast<ARMWord>(cc) | MVN | SET_CC, rd, ARMRegisters::r0, op2); } void mul_r(int rd, int rn, int rm, Condition cc = AL) @@ -382,6 +401,11 @@ namespace ARM { emitInst(static_cast<ARMWord>(cc) | FADDD, dd, dn, dm); } + void fdivd_r(int dd, int dn, int dm, Condition cc = AL) + { + emitInst(static_cast<ARMWord>(cc) | FDIVD, dd, dn, dm); + } + void fsubd_r(int dd, int dn, int dm, Condition cc = AL) { emitInst(static_cast<ARMWord>(cc) | FSUBD, dd, dn, dm); @@ -399,12 +423,12 @@ namespace ARM { void ldr_imm(int rd, ARMWord imm, Condition cc = AL) { - m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARM::pc) | RD(rd), imm, true); + m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm, true); } void ldr_un_imm(int rd, ARMWord imm, Condition cc = AL) { - m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARM::pc) | RD(rd), imm); + m_buffer.putIntWithConstantInt(static_cast<ARMWord>(cc) | DTR | DT_LOAD | DT_UP | RN(ARMRegisters::pc) | RD(rd), imm); } void dtr_u(bool isLoad, int rd, int rb, ARMWord op2, Condition cc = AL) @@ -462,23 +486,23 @@ namespace ARM { void push_r(int reg, Condition cc = AL) { ASSERT(ARMWord(reg) <= 0xf); - m_buffer.putInt(cc | DTR | DT_WB | RN(ARM::sp) | RD(reg) | 0x4); + m_buffer.putInt(cc | DTR | DT_WB | RN(ARMRegisters::sp) | RD(reg) | 0x4); } void pop_r(int reg, Condition cc = AL) { ASSERT(ARMWord(reg) <= 0xf); - m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARM::sp) | RD(reg) | 0x4); + m_buffer.putInt(cc | (DTR ^ DT_PRE) | DT_LOAD | DT_UP | RN(ARMRegisters::sp) | RD(reg) | 0x4); } inline void poke_r(int reg, Condition cc = AL) { - dtr_d(false, ARM::sp, 0, reg, cc); + dtr_d(false, ARMRegisters::sp, 0, reg, cc); } inline void peek_r(int reg, Condition cc = AL) { - dtr_u(true, reg, ARM::sp, 0, cc); + dtr_u(true, reg, ARMRegisters::sp, 0, cc); } void fmsr_r(int dd, int rn, Condition cc = AL) @@ -486,11 +510,21 @@ namespace ARM { emitInst(static_cast<ARMWord>(cc) | FMSR, rn, dd, 0); } + void fmrs_r(int rd, int dn, Condition cc = AL) + { + emitInst(static_cast<ARMWord>(cc) | FMRS, rd, dn, 0); + } + void fsitod_r(int dd, int dm, Condition cc = AL) { emitInst(static_cast<ARMWord>(cc) | FSITOD, dd, 0, dm); } + void ftosid_r(int fd, int dm, Condition cc = AL) + { + emitInst(static_cast<ARMWord>(cc) | FTOSID, fd, 0, dm); + } + void fmstat(Condition cc = AL) { m_buffer.putInt(static_cast<ARMWord>(cc) | FMSTAT); @@ -509,49 +543,49 @@ namespace ARM { m_buffer.putInt(BKPT | ((value & 0xff0) << 4) | (value & 0xf)); #else // Cannot access to Zero memory address - dtr_dr(true, ARM::S0, ARM::S0, ARM::S0); + dtr_dr(true, ARMRegisters::S0, ARMRegisters::S0, ARMRegisters::S0); #endif } static ARMWord lsl(int reg, ARMWord value) { - ASSERT(reg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); ASSERT(value <= 0x1f); return reg | (value << 7) | 0x00; } static ARMWord lsr(int reg, ARMWord value) { - ASSERT(reg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); ASSERT(value <= 0x1f); return reg | (value << 7) | 0x20; } static ARMWord asr(int reg, ARMWord value) { - ASSERT(reg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); ASSERT(value <= 0x1f); return reg | (value << 7) | 0x40; } static ARMWord lsl_r(int reg, int shiftReg) { - ASSERT(reg <= ARM::pc); - ASSERT(shiftReg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); + ASSERT(shiftReg <= ARMRegisters::pc); return reg | (shiftReg << 8) | 0x10; } static ARMWord lsr_r(int reg, int shiftReg) { - ASSERT(reg <= ARM::pc); - ASSERT(shiftReg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); + ASSERT(shiftReg <= ARMRegisters::pc); return reg | (shiftReg << 8) | 0x30; } static ARMWord asr_r(int reg, int shiftReg) { - ASSERT(reg <= ARM::pc); - ASSERT(shiftReg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); + ASSERT(shiftReg <= ARMRegisters::pc); return reg | (shiftReg << 8) | 0x50; } @@ -567,6 +601,11 @@ namespace ARM { m_buffer.ensureSpace(insnSpace, constSpace); } + int sizeOfConstantPool() + { + return m_buffer.sizeOfConstantPool(); + } + JmpDst label() { return JmpDst(m_buffer.size()); @@ -575,16 +614,17 @@ namespace ARM { JmpDst align(int alignment) { while (!m_buffer.isAligned(alignment)) - mov_r(ARM::r0, ARM::r0); + mov_r(ARMRegisters::r0, ARMRegisters::r0); return label(); } - JmpSrc jmp(Condition cc = AL) + JmpSrc jmp(Condition cc = AL, int useConstantPool = 0) { - int s = size(); - ldr_un_imm(ARM::pc, 0xffffffff, cc); - m_jumps.append(s); + ensureSpace(sizeof(ARMWord), sizeof(ARMWord)); + int s = m_buffer.uncheckedSize(); + ldr_un_imm(ARMRegisters::pc, 0xffffffff, cc); + m_jumps.append(s | (useConstantPool & 0x1)); return JmpSrc(s); } @@ -593,7 +633,7 @@ namespace ARM { // Patching helpers static ARMWord* getLdrImmAddress(ARMWord* insn, uint32_t* constPool = 0); - static void linkBranch(void* code, JmpSrc from, void* to); + static void linkBranch(void* code, JmpSrc from, void* to, int useConstantPool = 0); static void patchPointerInternal(intptr_t from, void* to) { @@ -660,7 +700,7 @@ namespace ARM { static void linkCall(void* code, JmpSrc from, void* to) { - linkBranch(code, from, to); + linkBranch(code, from, to, true); } static void relinkCall(void* from, void* to) @@ -706,8 +746,18 @@ namespace ARM { } static ARMWord getOp2(ARMWord imm); + +#if ARM_ARCH_VERSION >= 7 + static ARMWord getImm16Op2(ARMWord imm) + { + if (imm <= 0xffff) + return (imm & 0xf000) << 4 | (imm & 0xfff); + return INVALID_IMM; + } +#endif ARMWord getImm(ARMWord imm, int tmpReg, bool invert = false); void moveImm(ARMWord imm, int dest); + ARMWord encodeComplexImm(ARMWord imm, int dest); // Memory load/store helpers @@ -727,25 +777,25 @@ namespace ARM { private: ARMWord RM(int reg) { - ASSERT(reg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); return reg; } ARMWord RS(int reg) { - ASSERT(reg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); return reg << 8; } ARMWord RD(int reg) { - ASSERT(reg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); return reg << 12; } ARMWord RN(int reg) { - ASSERT(reg <= ARM::pc); + ASSERT(reg <= ARMRegisters::pc); return reg << 16; } @@ -762,6 +812,6 @@ namespace ARM { } // namespace JSC -#endif // ENABLE(ASSEMBLER) && PLATFORM(ARM) +#endif // ENABLE(ASSEMBLER) && PLATFORM(ARM_TRADITIONAL) #endif // ARMAssembler_h diff --git a/JavaScriptCore/assembler/ARMv7Assembler.h b/JavaScriptCore/assembler/ARMv7Assembler.h index f7e2fb4..e253a53 100644 --- a/JavaScriptCore/assembler/ARMv7Assembler.h +++ b/JavaScriptCore/assembler/ARMv7Assembler.h @@ -28,7 +28,7 @@ #include <wtf/Platform.h> -#if ENABLE(ASSEMBLER) && PLATFORM_ARM_ARCH(7) +#if ENABLE(ASSEMBLER) && PLATFORM(ARM_THUMB2) #include "AssemblerBuffer.h" #include <wtf/Assertions.h> @@ -37,7 +37,7 @@ namespace JSC { -namespace ARM { +namespace ARMRegisters { typedef enum { r0, r1, @@ -199,7 +199,7 @@ class ARMThumbImmediate { }; } PatternBytes; - ALWAYS_INLINE static int32_t countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N) + ALWAYS_INLINE static void countLeadingZerosPartial(uint32_t& value, int32_t& zeros, const int N) { if (value & ~((1<<N)-1)) /* check for any of the top N bits (of 2N bits) are set */ \ value >>= N; /* if any were set, lose the bottom N */ \ @@ -236,6 +236,11 @@ class ARMThumbImmediate { ARMThumbImmediate(ThumbImmediateType type, uint16_t value) : m_type(TypeUInt16) { + // Make sure this constructor is only reached with type TypeUInt16; + // this extra parameter makes the code a little clearer by making it + // explicit at call sites which type is being constructed + ASSERT_UNUSED(type, type == TypeUInt16); + m_value.asInt = value; } @@ -407,8 +412,13 @@ register writeback class ARMv7Assembler { public: - typedef ARM::RegisterID RegisterID; - typedef ARM::FPRegisterID FPRegisterID; + ~ARMv7Assembler() + { + ASSERT(m_jumpsToLink.isEmpty()); + } + + typedef ARMRegisters::RegisterID RegisterID; + typedef ARMRegisters::FPRegisterID FPRegisterID; // (HS, LO, HI, LS) -> (AE, B, A, BE) // (VS, VC) -> (O, NO) @@ -442,7 +452,6 @@ public: { } - void enableLatePatch() { } private: JmpSrc(int offset) : m_offset(offset) @@ -478,10 +487,21 @@ public: private: + struct LinkRecord { + LinkRecord(intptr_t from, intptr_t to) + : from(from) + , to(to) + { + } + + intptr_t from; + intptr_t to; + }; + // ARMv7, Appx-A.6.3 bool BadReg(RegisterID reg) { - return (reg == ARM::sp) || (reg == ARM::pc); + return (reg == ARMRegisters::sp) || (reg == ARMRegisters::pc); } bool isSingleRegister(FPRegisterID reg) @@ -575,6 +595,7 @@ private: OP_SUB_SP_imm_T1 = 0xB080, OP_BKPT = 0xBE00, OP_IT = 0xBF00, + OP_NOP_T1 = 0xBF00, } OpcodeID; typedef enum { @@ -609,6 +630,7 @@ private: OP_MOV_imm_T3 = 0xF240, OP_SUB_imm_T4 = 0xF2A0, OP_MOVT = 0xF2C0, + OP_NOP_T2a = 0xF3AF, OP_LDRH_reg_T2 = 0xF830, OP_LDRH_imm_T3 = 0xF830, OP_STR_imm_T4 = 0xF840, @@ -627,6 +649,7 @@ private: typedef enum { OP_B_T4b = 0x9000, + OP_NOP_T2b = 0x8000, } OpcodeID2; struct FourFours { @@ -693,16 +716,16 @@ public: void add(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) { // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARM::sp) || (rn == ARM::sp)); - ASSERT(rd != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(imm.isValid()); - if (rn == ARM::sp) { + if (rn == ARMRegisters::sp) { if (!(rd & 8) && imm.isUInt10()) { m_formatter.oneWordOp5Reg3Imm8(OP_ADD_SP_imm_T1, rd, imm.getUInt10() >> 2); return; - } else if ((rd == ARM::sp) && imm.isUInt9()) { + } else if ((rd == ARMRegisters::sp) && imm.isUInt9()) { m_formatter.oneWordOp9Imm7(OP_ADD_SP_imm_T2, imm.getUInt9() >> 2); return; } @@ -726,9 +749,9 @@ public: void add(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) { - ASSERT((rd != ARM::sp) || (rn == ARM::sp)); - ASSERT(rd != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(!BadReg(rm)); m_formatter.twoWordOp12Reg4FourFours(OP_ADD_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); } @@ -750,9 +773,9 @@ public: void add_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) { // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARM::sp) || (rn == ARM::sp)); - ASSERT(rd != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(imm.isEncodedImm()); if (!((rd | rn) & 8)) { @@ -771,9 +794,9 @@ public: // Not allowed in an IT (if then) block? void add_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) { - ASSERT((rd != ARM::sp) || (rn == ARM::sp)); - ASSERT(rd != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(!BadReg(rm)); m_formatter.twoWordOp12Reg4FourFours(OP_ADD_S_reg_T3, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); } @@ -839,7 +862,7 @@ public: // Only allowed in IT (if then) block if last instruction. JmpSrc blx(RegisterID rm) { - ASSERT(rm != ARM::pc); + ASSERT(rm != ARMRegisters::pc); m_formatter.oneWordOp8RegReg143(OP_BLX, rm, (RegisterID)8); return JmpSrc(m_formatter.size()); } @@ -858,7 +881,7 @@ public: void cmn(RegisterID rn, ARMThumbImmediate imm) { - ASSERT(rn != ARM::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(imm.isEncodedImm()); m_formatter.twoWordOp5i6Imm4Reg4EncodedImm(OP_CMN_imm, rn, (RegisterID)0xf, imm); @@ -866,7 +889,7 @@ public: void cmp(RegisterID rn, ARMThumbImmediate imm) { - ASSERT(rn != ARM::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(imm.isEncodedImm()); if (!(rn & 8) && imm.isUInt8()) @@ -877,7 +900,7 @@ public: void cmp(RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) { - ASSERT(rn != ARM::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(!BadReg(rm)); m_formatter.twoWordOp12Reg4FourFours(OP_CMP_reg_T2, rn, FourFours(shift.hi4(), 0xf, shift.lo4(), rm)); } @@ -939,15 +962,15 @@ public: m_formatter.oneWordOp8Imm8(OP_IT, ifThenElse(cond, inst2if, inst3if, inst4if)); } - // rt == ARM::pc only allowed if last instruction in IT (if then) block. + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. void ldr(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) { - ASSERT(rn != ARM::pc); // LDR (literal) + ASSERT(rn != ARMRegisters::pc); // LDR (literal) ASSERT(imm.isUInt12()); if (!((rt | rn) & 8) && imm.isUInt7()) m_formatter.oneWordOp5Imm5Reg3Reg3(OP_LDR_imm_T1, imm.getUInt7() >> 2, rn, rt); - else if ((rn == ARM::sp) && !(rt & 8) && imm.isUInt10()) + else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) m_formatter.oneWordOp5Reg3Imm8(OP_LDR_imm_T2, rt, imm.getUInt10() >> 2); else m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T3, rn, rt, imm.getUInt12()); @@ -966,8 +989,8 @@ public: // if (wback) REG[rn] = _tmp void ldr(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) { - ASSERT(rt != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(index || wback); ASSERT(!wback | (rt != rn)); @@ -986,10 +1009,10 @@ public: m_formatter.twoWordOp12Reg4Reg4Imm12(OP_LDR_imm_T4, rn, rt, offset); } - // rt == ARM::pc only allowed if last instruction in IT (if then) block. + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. void ldr(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) { - ASSERT(rn != ARM::pc); // LDR (literal) + ASSERT(rn != ARMRegisters::pc); // LDR (literal) ASSERT(!BadReg(rm)); ASSERT(shift <= 3); @@ -999,10 +1022,10 @@ public: m_formatter.twoWordOp12Reg4FourFours(OP_LDR_reg_T2, rn, FourFours(rt, 0, shift, rm)); } - // rt == ARM::pc only allowed if last instruction in IT (if then) block. + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. void ldrh(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) { - ASSERT(rn != ARM::pc); // LDR (literal) + ASSERT(rn != ARMRegisters::pc); // LDR (literal) ASSERT(imm.isUInt12()); if (!((rt | rn) & 8) && imm.isUInt6()) @@ -1024,8 +1047,8 @@ public: // if (wback) REG[rn] = _tmp void ldrh(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) { - ASSERT(rt != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(index || wback); ASSERT(!wback | (rt != rn)); @@ -1047,7 +1070,7 @@ public: void ldrh(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) { ASSERT(!BadReg(rt)); // Memory hint - ASSERT(rn != ARM::pc); // LDRH (literal) + ASSERT(rn != ARMRegisters::pc); // LDRH (literal) ASSERT(!BadReg(rm)); ASSERT(shift <= 3); @@ -1198,16 +1221,16 @@ public: m_formatter.twoWordOp12Reg4FourFours(OP_SMULL_T1, rn, FourFours(rdLo, rdHi, 0, rm)); } - // rt == ARM::pc only allowed if last instruction in IT (if then) block. + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. void str(RegisterID rt, RegisterID rn, ARMThumbImmediate imm) { - ASSERT(rt != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(imm.isUInt12()); if (!((rt | rn) & 8) && imm.isUInt7()) m_formatter.oneWordOp5Imm5Reg3Reg3(OP_STR_imm_T1, imm.getUInt7() >> 2, rn, rt); - else if ((rn == ARM::sp) && !(rt & 8) && imm.isUInt10()) + else if ((rn == ARMRegisters::sp) && !(rt & 8) && imm.isUInt10()) m_formatter.oneWordOp5Reg3Imm8(OP_STR_imm_T2, rt, imm.getUInt10() >> 2); else m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T3, rn, rt, imm.getUInt12()); @@ -1226,8 +1249,8 @@ public: // if (wback) REG[rn] = _tmp void str(RegisterID rt, RegisterID rn, int offset, bool index, bool wback) { - ASSERT(rt != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT(rt != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(index || wback); ASSERT(!wback | (rt != rn)); @@ -1246,10 +1269,10 @@ public: m_formatter.twoWordOp12Reg4Reg4Imm12(OP_STR_imm_T4, rn, rt, offset); } - // rt == ARM::pc only allowed if last instruction in IT (if then) block. + // rt == ARMRegisters::pc only allowed if last instruction in IT (if then) block. void str(RegisterID rt, RegisterID rn, RegisterID rm, unsigned shift=0) { - ASSERT(rn != ARM::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(!BadReg(rm)); ASSERT(shift <= 3); @@ -1262,12 +1285,12 @@ public: void sub(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) { // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARM::sp) || (rn == ARM::sp)); - ASSERT(rd != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(imm.isValid()); - if ((rn == ARM::sp) && (rd == ARM::sp) && imm.isUInt9()) { + if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2); return; } else if (!((rd | rn) & 8)) { @@ -1290,9 +1313,9 @@ public: void sub(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) { - ASSERT((rd != ARM::sp) || (rn == ARM::sp)); - ASSERT(rd != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(!BadReg(rm)); m_formatter.twoWordOp12Reg4FourFours(OP_SUB_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); } @@ -1310,12 +1333,12 @@ public: void sub_S(RegisterID rd, RegisterID rn, ARMThumbImmediate imm) { // Rd can only be SP if Rn is also SP. - ASSERT((rd != ARM::sp) || (rn == ARM::sp)); - ASSERT(rd != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(imm.isValid()); - if ((rn == ARM::sp) && (rd == ARM::sp) && imm.isUInt9()) { + if ((rn == ARMRegisters::sp) && (rd == ARMRegisters::sp) && imm.isUInt9()) { m_formatter.oneWordOp9Imm7(OP_SUB_SP_imm_T1, imm.getUInt9() >> 2); return; } else if (!((rd | rn) & 8)) { @@ -1334,9 +1357,9 @@ public: // Not allowed in an IT (if then) block? void sub_S(RegisterID rd, RegisterID rn, RegisterID rm, ShiftTypeAndAmount shift) { - ASSERT((rd != ARM::sp) || (rn == ARM::sp)); - ASSERT(rd != ARM::pc); - ASSERT(rn != ARM::pc); + ASSERT((rd != ARMRegisters::sp) || (rn == ARMRegisters::sp)); + ASSERT(rd != ARMRegisters::pc); + ASSERT(rn != ARMRegisters::pc); ASSERT(!BadReg(rm)); m_formatter.twoWordOp12Reg4FourFours(OP_SUB_S_reg_T2, rn, FourFours(shift.hi4(), rd, shift.lo4(), rm)); } @@ -1482,6 +1505,15 @@ public: void* executableCopy(ExecutablePool* allocator) { void* copy = m_formatter.executableCopy(allocator); + + unsigned jumpCount = m_jumpsToLink.size(); + for (unsigned i = 0; i < jumpCount; ++i) { + uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(copy) + m_jumpsToLink[i].from); + uint16_t* target = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(copy) + m_jumpsToLink[i].to); + linkJumpAbsolute(location, target); + } + m_jumpsToLink.clear(); + ASSERT(copy); return copy; } @@ -1504,11 +1536,7 @@ public: { ASSERT(to.m_offset != -1); ASSERT(from.m_offset != -1); - - uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(m_formatter.data()) + from.m_offset); - intptr_t relative = to.m_offset - from.m_offset; - - linkWithOffset(location, relative); + m_jumpsToLink.append(LinkRecord(from.m_offset, to.m_offset)); } static void linkJump(void* code, JmpSrc from, void* to) @@ -1516,9 +1544,7 @@ public: ASSERT(from.m_offset != -1); uint16_t* location = reinterpret_cast<uint16_t*>(reinterpret_cast<intptr_t>(code) + from.m_offset); - intptr_t relative = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(location); - - linkWithOffset(location, relative); + linkJumpAbsolute(location, to); } // bah, this mathod should really be static, since it is used by the LinkBuffer. @@ -1542,10 +1568,9 @@ public: ASSERT(!(reinterpret_cast<intptr_t>(from) & 1)); ASSERT(!(reinterpret_cast<intptr_t>(to) & 1)); - intptr_t relative = reinterpret_cast<intptr_t>(to) - reinterpret_cast<intptr_t>(from); - linkWithOffset(reinterpret_cast<uint16_t*>(from), relative); + linkJumpAbsolute(reinterpret_cast<uint16_t*>(from), to); - ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 2, 2 * sizeof(uint16_t)); + ExecutableAllocator::cacheFlush(reinterpret_cast<uint16_t*>(from) - 5, 5 * sizeof(uint16_t)); } static void relinkCall(void* from, void* to) @@ -1614,14 +1639,14 @@ private: static void setInt32(void* code, uint32_t value) { uint16_t* location = reinterpret_cast<uint16_t*>(code); + ASSERT(isMOV_imm_T3(location - 4) && isMOVT(location - 2)); - uint16_t lo16 = value; - uint16_t hi16 = value >> 16; - - spliceHi5(location - 4, lo16); - spliceLo11(location - 3, lo16); - spliceHi5(location - 2, hi16); - spliceLo11(location - 1, hi16); + ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value)); + ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(value >> 16)); + location[-4] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); + location[-3] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-3] >> 8) & 0xf, lo16); + location[-2] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); + location[-1] = twoWordOp5i6Imm4Reg4EncodedImmSecond((location[-1] >> 8) & 0xf, hi16); ExecutableAllocator::cacheFlush(location - 4, 4 * sizeof(uint16_t)); } @@ -1631,41 +1656,89 @@ private: setInt32(code, reinterpret_cast<uint32_t>(value)); } - // Linking & patching: - // This method assumes that the JmpSrc being linked is a T4 b instruction. - static void linkWithOffset(uint16_t* instruction, intptr_t relative) - { - // Currently branches > 16m = mostly deathy. - if (((relative << 7) >> 7) != relative) { - // FIXME: This CRASH means we cannot turn the JIT on by default on arm-v7. - fprintf(stderr, "Error: Cannot link T4b.\n"); - CRASH(); - } - - // ARM encoding for the top two bits below the sign bit is 'peculiar'. - if (relative >= 0) - relative ^= 0xC00000; + static bool isB(void* address) + { + uint16_t* instruction = static_cast<uint16_t*>(address); + return ((instruction[0] & 0xf800) == OP_B_T4a) && ((instruction[1] & 0xd000) == OP_B_T4b); + } - // All branch offsets should be an even distance. - ASSERT(!(relative & 1)); + static bool isBX(void* address) + { + uint16_t* instruction = static_cast<uint16_t*>(address); + return (instruction[0] & 0xff87) == OP_BX; + } - int word1 = ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12); - int word2 = ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1); + static bool isMOV_imm_T3(void* address) + { + uint16_t* instruction = static_cast<uint16_t*>(address); + return ((instruction[0] & 0xFBF0) == OP_MOV_imm_T3) && ((instruction[1] & 0x8000) == 0); + } - instruction[-2] = OP_B_T4a | word1; - instruction[-1] = OP_B_T4b | word2; + static bool isMOVT(void* address) + { + uint16_t* instruction = static_cast<uint16_t*>(address); + return ((instruction[0] & 0xFBF0) == OP_MOVT) && ((instruction[1] & 0x8000) == 0); } - // These functions can be used to splice 16-bit immediates back into previously generated instructions. - static void spliceHi5(uint16_t* where, uint16_t what) + static bool isNOP_T1(void* address) { - uint16_t pattern = (what >> 12) | ((what & 0x0800) >> 1); - *where = (*where & 0xFBF0) | pattern; + uint16_t* instruction = static_cast<uint16_t*>(address); + return instruction[0] == OP_NOP_T1; } - static void spliceLo11(uint16_t* where, uint16_t what) + + static bool isNOP_T2(void* address) { - uint16_t pattern = ((what & 0x0700) << 4) | (what & 0x00FF); - *where = (*where & 0x8F00) | pattern; + uint16_t* instruction = static_cast<uint16_t*>(address); + return (instruction[0] == OP_NOP_T2a) && (instruction[1] == OP_NOP_T2b); + } + + static void linkJumpAbsolute(uint16_t* instruction, void* target) + { + // FIMXE: this should be up in the MacroAssembler layer. :-( + const uint16_t JUMP_TEMPORARY_REGISTER = ARMRegisters::ip; + + ASSERT(!(reinterpret_cast<intptr_t>(instruction) & 1)); + ASSERT(!(reinterpret_cast<intptr_t>(target) & 1)); + + ASSERT( (isMOV_imm_T3(instruction - 5) && isMOVT(instruction - 3) && isBX(instruction - 1)) + || (isNOP_T1(instruction - 5) && isNOP_T2(instruction - 4) && isB(instruction - 2)) ); + + intptr_t relative = reinterpret_cast<intptr_t>(target) - (reinterpret_cast<intptr_t>(instruction)); + if (((relative << 7) >> 7) == relative) { + // ARM encoding for the top two bits below the sign bit is 'peculiar'. + if (relative >= 0) + relative ^= 0xC00000; + + // All branch offsets should be an even distance. + ASSERT(!(relative & 1)); + // There may be a better way to fix this, but right now put the NOPs first, since in the + // case of an conditional branch this will be coming after an ITTT predicating *three* + // instructions! Looking backwards to modify the ITTT to an IT is not easy, due to + // variable wdith encoding - the previous instruction might *look* like an ITTT but + // actually be the second half of a 2-word op. + instruction[-5] = OP_NOP_T1; + instruction[-4] = OP_NOP_T2a; + instruction[-3] = OP_NOP_T2b; + instruction[-2] = OP_B_T4a | ((relative & 0x1000000) >> 14) | ((relative & 0x3ff000) >> 12); + instruction[-1] = OP_B_T4b | ((relative & 0x800000) >> 10) | ((relative & 0x400000) >> 11) | ((relative & 0xffe) >> 1); + } else { + ARMThumbImmediate lo16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) + 1)); + ARMThumbImmediate hi16 = ARMThumbImmediate::makeUInt16(static_cast<uint16_t>(reinterpret_cast<uint32_t>(target) >> 16)); + instruction[-5] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOV_imm_T3, lo16); + instruction[-4] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, lo16); + instruction[-3] = twoWordOp5i6Imm4Reg4EncodedImmFirst(OP_MOVT, hi16); + instruction[-2] = twoWordOp5i6Imm4Reg4EncodedImmSecond(JUMP_TEMPORARY_REGISTER, hi16); + instruction[-1] = OP_BX | (JUMP_TEMPORARY_REGISTER << 3); + } + } + + static uint16_t twoWordOp5i6Imm4Reg4EncodedImmFirst(uint16_t op, ARMThumbImmediate imm) + { + return op | (imm.m_value.i << 10) | imm.m_value.imm4; + } + static uint16_t twoWordOp5i6Imm4Reg4EncodedImmSecond(uint16_t rd, ARMThumbImmediate imm) + { + return (imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8; } class ARMInstructionFormatter { @@ -1724,8 +1797,11 @@ private: void twoWordOp5i6Imm4Reg4EncodedImm(OpcodeID1 op, int imm4, RegisterID rd, ARMThumbImmediate imm) { - m_buffer.putShort(op | (imm.m_value.i << 10) | imm4); - m_buffer.putShort((imm.m_value.imm3 << 12) | (rd << 8) | imm.m_value.imm8); + ARMThumbImmediate newImm = imm; + newImm.m_value.imm4 = imm4; + + m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmFirst(op, newImm)); + m_buffer.putShort(ARMv7Assembler::twoWordOp5i6Imm4Reg4EncodedImmSecond(rd, newImm)); } void twoWordOp12Reg4Reg4Imm12(OpcodeID1 op, RegisterID reg1, RegisterID reg2, uint16_t imm) @@ -1750,10 +1826,12 @@ private: private: AssemblerBuffer m_buffer; } m_formatter; + + Vector<LinkRecord> m_jumpsToLink; }; } // namespace JSC -#endif // ENABLE(ASSEMBLER) && PLATFORM_ARM_ARCH(7) +#endif // ENABLE(ASSEMBLER) && PLATFORM(ARM_THUMB2) #endif // ARMAssembler_h diff --git a/JavaScriptCore/assembler/AbstractMacroAssembler.h b/JavaScriptCore/assembler/AbstractMacroAssembler.h index f927ed2..525fe98 100644 --- a/JavaScriptCore/assembler/AbstractMacroAssembler.h +++ b/JavaScriptCore/assembler/AbstractMacroAssembler.h @@ -320,11 +320,6 @@ public: return Call(jump.m_jmp, Linkable); } - void enableLatePatch() - { - m_jmp.enableLatePatch(); - } - JmpSrc m_jmp; private: Flags m_flags; @@ -361,11 +356,6 @@ public: masm->m_assembler.linkJump(m_jmp, label.m_label); } - void enableLatePatch() - { - m_jmp.enableLatePatch(); - } - private: JmpSrc m_jmp; }; diff --git a/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h b/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h index f15b7f3..af3c3be 100644 --- a/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h +++ b/JavaScriptCore/assembler/AssemblerBufferWithConstantPool.h @@ -34,6 +34,8 @@ #include "AssemblerBuffer.h" #include <wtf/SegmentedVector.h> +#define ASSEMBLER_HAS_CONSTANT_POOL 1 + namespace JSC { /* @@ -84,7 +86,7 @@ namespace JSC { template <int maxPoolSize, int barrierSize, int maxInstructionSize, class AssemblerType> class AssemblerBufferWithConstantPool: public AssemblerBuffer { - typedef WTF::SegmentedVector<uint32_t, 512> LoadOffsets; + typedef SegmentedVector<uint32_t, 512> LoadOffsets; public: enum { UniqueConst, @@ -177,6 +179,11 @@ public: return AssemblerBuffer::size(); } + int uncheckedSize() + { + return AssemblerBuffer::size(); + } + void* executableCopy(ExecutablePool* allocator) { flushConstantPool(false); @@ -207,10 +214,10 @@ public: } // This flushing mechanism can be called after any unconditional jumps. - void flushWithoutBarrier() + void flushWithoutBarrier(bool isForced = false) { // Flush if constant pool is more than 60% full to avoid overuse of this function. - if (5 * m_numConsts > 3 * maxPoolSize / sizeof(uint32_t)) + if (isForced || 5 * m_numConsts > 3 * maxPoolSize / sizeof(uint32_t)) flushConstantPool(false); } @@ -219,6 +226,11 @@ public: return m_pool; } + int sizeOfConstantPool() + { + return m_numConsts; + } + private: void correctDeltas(int insnSize) { @@ -276,7 +288,8 @@ private: { if (m_numConsts == 0) return; - if ((m_maxDistance < nextInsnSize + m_lastConstDelta + barrierSize + (int)sizeof(uint32_t))) + int lastConstDelta = m_lastConstDelta > nextInsnSize ? m_lastConstDelta - nextInsnSize : 0; + if ((m_maxDistance < nextInsnSize + lastConstDelta + barrierSize + (int)sizeof(uint32_t))) flushConstantPool(); } @@ -284,8 +297,8 @@ private: { if (m_numConsts == 0) return; - if ((m_maxDistance < nextInsnSize + m_lastConstDelta + barrierSize + (int)sizeof(uint32_t)) || - (m_numConsts + nextConstSize / sizeof(uint32_t) >= maxPoolSize)) + if ((m_maxDistance < nextInsnSize + m_lastConstDelta + nextConstSize + barrierSize + (int)sizeof(uint32_t)) || + (m_numConsts * sizeof(uint32_t) + nextConstSize >= maxPoolSize)) flushConstantPool(); } diff --git a/JavaScriptCore/assembler/MacroAssembler.h b/JavaScriptCore/assembler/MacroAssembler.h index 9e1c5d3..858707d 100644 --- a/JavaScriptCore/assembler/MacroAssembler.h +++ b/JavaScriptCore/assembler/MacroAssembler.h @@ -30,11 +30,11 @@ #if ENABLE(ASSEMBLER) -#if PLATFORM_ARM_ARCH(7) +#if PLATFORM(ARM_THUMB2) #include "MacroAssemblerARMv7.h" namespace JSC { typedef MacroAssemblerARMv7 MacroAssemblerBase; }; -#elif PLATFORM(ARM) +#elif PLATFORM(ARM_TRADITIONAL) #include "MacroAssemblerARM.h" namespace JSC { typedef MacroAssemblerARM MacroAssemblerBase; }; @@ -179,16 +179,6 @@ public: or32(imm, dest); } - void rshiftPtr(RegisterID shift_amount, RegisterID dest) - { - rshift32(shift_amount, dest); - } - - void rshiftPtr(Imm32 imm, RegisterID dest) - { - rshift32(imm, dest); - } - void subPtr(RegisterID src, RegisterID dest) { sub32(src, dest); diff --git a/JavaScriptCore/assembler/MacroAssemblerARM.cpp b/JavaScriptCore/assembler/MacroAssemblerARM.cpp new file mode 100644 index 0000000..d726ecd --- /dev/null +++ b/JavaScriptCore/assembler/MacroAssemblerARM.cpp @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2009 University of Szeged + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY UNIVERSITY OF SZEGED ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL UNIVERSITY OF SZEGED OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" + +#if ENABLE(ASSEMBLER) && PLATFORM(ARM_TRADITIONAL) + +#include "MacroAssemblerARM.h" + +#if PLATFORM(LINUX) +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <unistd.h> +#include <elf.h> +#include <asm/hwcap.h> +#endif + +namespace JSC { + +static bool isVFPPresent() +{ +#if PLATFORM(LINUX) + int fd = open("/proc/self/auxv", O_RDONLY); + if (fd > 0) { + Elf32_auxv_t aux; + while (read(fd, &aux, sizeof(Elf32_auxv_t))) { + if (aux.a_type == AT_HWCAP) { + close(fd); + return aux.a_un.a_val & HWCAP_VFP; + } + } + close(fd); + } +#endif + + return false; +} + +const bool MacroAssemblerARM::s_isVFPPresent = isVFPPresent(); + +#if defined(ARM_REQUIRE_NATURAL_ALIGNMENT) && ARM_REQUIRE_NATURAL_ALIGNMENT +void MacroAssemblerARM::load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) +{ + ARMWord op2; + + ASSERT(address.scale >= 0 && address.scale <= 3); + op2 = m_assembler.lsl(address.index, static_cast<int>(address.scale)); + + if (address.offset >= 0 && address.offset + 0x2 <= 0xff) { + m_assembler.add_r(ARMRegisters::S0, address.base, op2); + m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset)); + m_assembler.ldrh_u(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset + 0x2)); + } else if (address.offset < 0 && address.offset >= -0xff) { + m_assembler.add_r(ARMRegisters::S0, address.base, op2); + m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset)); + m_assembler.ldrh_d(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset - 0x2)); + } else { + m_assembler.ldr_un_imm(ARMRegisters::S0, address.offset); + m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, op2); + m_assembler.ldrh_r(dest, address.base, ARMRegisters::S0); + m_assembler.add_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::OP2_IMM | 0x2); + m_assembler.ldrh_r(ARMRegisters::S0, address.base, ARMRegisters::S0); + } + m_assembler.orr_r(dest, dest, m_assembler.lsl(ARMRegisters::S0, 16)); +} +#endif + +} + +#endif // ENABLE(ASSEMBLER) && PLATFORM(ARM_TRADITIONAL) diff --git a/JavaScriptCore/assembler/MacroAssemblerARM.h b/JavaScriptCore/assembler/MacroAssemblerARM.h index b04ed13..24e2e11 100644 --- a/JavaScriptCore/assembler/MacroAssemblerARM.h +++ b/JavaScriptCore/assembler/MacroAssemblerARM.h @@ -30,7 +30,7 @@ #include <wtf/Platform.h> -#if ENABLE(ASSEMBLER) && PLATFORM(ARM) +#if ENABLE(ASSEMBLER) && PLATFORM(ARM_TRADITIONAL) #include "ARMAssembler.h" #include "AbstractMacroAssembler.h" @@ -38,6 +38,9 @@ namespace JSC { class MacroAssemblerARM : public AbstractMacroAssembler<ARMAssembler> { + static const int DoubleConditionMask = 0x0f; + static const int DoubleConditionBitSpecial = 0x10; + COMPILE_ASSERT(!(DoubleConditionBitSpecial & DoubleConditionMask), DoubleConditionBitSpecial_should_not_interfere_with_ARMAssembler_Condition_codes); public: enum Condition { Equal = ARMAssembler::EQ, @@ -57,14 +60,24 @@ public: }; enum DoubleCondition { + // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. DoubleEqual = ARMAssembler::EQ, + DoubleNotEqual = ARMAssembler::NE | DoubleConditionBitSpecial, DoubleGreaterThan = ARMAssembler::GT, DoubleGreaterThanOrEqual = ARMAssembler::GE, - DoubleLessThan = ARMAssembler::LT, - DoubleLessThanOrEqual = ARMAssembler::LE, + DoubleLessThan = ARMAssembler::CC, + DoubleLessThanOrEqual = ARMAssembler::LS, + // If either operand is NaN, these conditions always evaluate to true. + DoubleEqualOrUnordered = ARMAssembler::EQ | DoubleConditionBitSpecial, + DoubleNotEqualOrUnordered = ARMAssembler::NE, + DoubleGreaterThanOrUnordered = ARMAssembler::HI, + DoubleGreaterThanOrEqualOrUnordered = ARMAssembler::CS, + DoubleLessThanOrUnordered = ARMAssembler::LT, + DoubleLessThanOrEqualOrUnordered = ARMAssembler::LE, }; - static const RegisterID stackPointerRegister = ARM::sp; + static const RegisterID stackPointerRegister = ARMRegisters::sp; + static const RegisterID linkRegister = ARMRegisters::lr; static const Scale ScalePtr = TimesFour; @@ -75,20 +88,20 @@ public: void add32(Imm32 imm, Address address) { - load32(address, ARM::S1); - add32(imm, ARM::S1); - store32(ARM::S1, address); + load32(address, ARMRegisters::S1); + add32(imm, ARMRegisters::S1); + store32(ARMRegisters::S1, address); } void add32(Imm32 imm, RegisterID dest) { - m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARM::S0)); + m_assembler.adds_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void add32(Address src, RegisterID dest) { - load32(src, ARM::S1); - add32(ARM::S1, dest); + load32(src, ARMRegisters::S1); + add32(ARMRegisters::S1, dest); } void and32(RegisterID src, RegisterID dest) @@ -98,36 +111,45 @@ public: void and32(Imm32 imm, RegisterID dest) { - ARMWord w = m_assembler.getImm(imm.m_value, ARM::S0, true); + ARMWord w = m_assembler.getImm(imm.m_value, ARMRegisters::S0, true); if (w & ARMAssembler::OP2_INV_IMM) m_assembler.bics_r(dest, dest, w & ~ARMAssembler::OP2_INV_IMM); else m_assembler.ands_r(dest, dest, w); } - void lshift32(Imm32 imm, RegisterID dest) + void lshift32(RegisterID shift_amount, RegisterID dest) { - m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); + ARMWord w = ARMAssembler::getOp2(0x1f); + ASSERT(w != ARMAssembler::INVALID_IMM); + m_assembler.and_r(ARMRegisters::S0, shift_amount, w); + + m_assembler.movs_r(dest, m_assembler.lsl_r(dest, ARMRegisters::S0)); } - void lshift32(RegisterID shift_amount, RegisterID dest) + void lshift32(Imm32 imm, RegisterID dest) { - m_assembler.movs_r(dest, m_assembler.lsl_r(dest, shift_amount)); + m_assembler.movs_r(dest, m_assembler.lsl(dest, imm.m_value & 0x1f)); } void mul32(RegisterID src, RegisterID dest) { if (src == dest) { - move(src, ARM::S0); - src = ARM::S0; + move(src, ARMRegisters::S0); + src = ARMRegisters::S0; } m_assembler.muls_r(dest, dest, src); } void mul32(Imm32 imm, RegisterID src, RegisterID dest) { - move(imm, ARM::S0); - m_assembler.muls_r(dest, src, ARM::S0); + move(imm, ARMRegisters::S0); + m_assembler.muls_r(dest, src, ARMRegisters::S0); + } + + void neg32(RegisterID srcDest) + { + m_assembler.rsbs_r(srcDest, srcDest, ARMAssembler::getOp2(0)); } void not32(RegisterID dest) @@ -142,12 +164,16 @@ public: void or32(Imm32 imm, RegisterID dest) { - m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARM::S0)); + m_assembler.orrs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void rshift32(RegisterID shift_amount, RegisterID dest) { - m_assembler.movs_r(dest, m_assembler.asr_r(dest, shift_amount)); + ARMWord w = ARMAssembler::getOp2(0x1f); + ASSERT(w != ARMAssembler::INVALID_IMM); + m_assembler.and_r(ARMRegisters::S0, shift_amount, w); + + m_assembler.movs_r(dest, m_assembler.asr_r(dest, ARMRegisters::S0)); } void rshift32(Imm32 imm, RegisterID dest) @@ -162,20 +188,20 @@ public: void sub32(Imm32 imm, RegisterID dest) { - m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARM::S0)); + m_assembler.subs_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void sub32(Imm32 imm, Address address) { - load32(address, ARM::S1); - sub32(imm, ARM::S1); - store32(ARM::S1, address); + load32(address, ARMRegisters::S1); + sub32(imm, ARMRegisters::S1); + store32(ARMRegisters::S1, address); } void sub32(Address src, RegisterID dest) { - load32(src, ARM::S1); - sub32(ARM::S1, dest); + load32(src, ARMRegisters::S1); + sub32(ARMRegisters::S1, dest); } void xor32(RegisterID src, RegisterID dest) @@ -185,7 +211,7 @@ public: void xor32(Imm32 imm, RegisterID dest) { - m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARM::S0)); + m_assembler.eors_r(dest, dest, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void load32(ImplicitAddress address, RegisterID dest) @@ -198,11 +224,20 @@ public: m_assembler.baseIndexTransfer32(true, dest, address.base, address.index, static_cast<int>(address.scale), address.offset); } +#if defined(ARM_REQUIRE_NATURAL_ALIGNMENT) && ARM_REQUIRE_NATURAL_ALIGNMENT + void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest); +#else + void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) + { + load32(address, dest); + } +#endif + DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) { DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARM::S0, 0); - m_assembler.dtr_ur(true, dest, address.base, ARM::S0); + m_assembler.ldr_un_imm(ARMRegisters::S0, 0); + m_assembler.dtr_ur(true, dest, address.base, ARMRegisters::S0); return dataLabel; } @@ -215,18 +250,18 @@ public: void load16(BaseIndex address, RegisterID dest) { - m_assembler.add_r(ARM::S0, address.base, m_assembler.lsl(address.index, address.scale)); + m_assembler.add_r(ARMRegisters::S0, address.base, m_assembler.lsl(address.index, address.scale)); if (address.offset>=0) - m_assembler.ldrh_u(dest, ARM::S0, ARMAssembler::getOp2Byte(address.offset)); + m_assembler.ldrh_u(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(address.offset)); else - m_assembler.ldrh_d(dest, ARM::S0, ARMAssembler::getOp2Byte(-address.offset)); + m_assembler.ldrh_d(dest, ARMRegisters::S0, ARMAssembler::getOp2Byte(-address.offset)); } DataLabel32 store32WithAddressOffsetPatch(RegisterID src, Address address) { DataLabel32 dataLabel(this); - m_assembler.ldr_un_imm(ARM::S0, 0); - m_assembler.dtr_ur(false, src, address.base, ARM::S0); + m_assembler.ldr_un_imm(ARMRegisters::S0, 0); + m_assembler.dtr_ur(false, src, address.base, ARMRegisters::S0); return dataLabel; } @@ -243,26 +278,26 @@ public: void store32(Imm32 imm, ImplicitAddress address) { if (imm.m_isPointer) - m_assembler.ldr_un_imm(ARM::S1, imm.m_value); + m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); else - move(imm, ARM::S1); - store32(ARM::S1, address); + move(imm, ARMRegisters::S1); + store32(ARMRegisters::S1, address); } void store32(RegisterID src, void* address) { - m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address)); - m_assembler.dtr_u(false, src, ARM::S0, 0); + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); + m_assembler.dtr_u(false, src, ARMRegisters::S0, 0); } void store32(Imm32 imm, void* address) { - m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address)); + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); if (imm.m_isPointer) - m_assembler.ldr_un_imm(ARM::S1, imm.m_value); + m_assembler.ldr_un_imm(ARMRegisters::S1, imm.m_value); else - m_assembler.moveImm(imm.m_value, ARM::S1); - m_assembler.dtr_u(false, ARM::S1, ARM::S0, 0); + m_assembler.moveImm(imm.m_value, ARMRegisters::S1); + m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); } void pop(RegisterID dest) @@ -277,14 +312,14 @@ public: void push(Address address) { - load32(address, ARM::S1); - push(ARM::S1); + load32(address, ARMRegisters::S1); + push(ARMRegisters::S1); } void push(Imm32 imm) { - move(imm, ARM::S0); - push(ARM::S0); + move(imm, ARMRegisters::S0); + push(ARMRegisters::S0); } void move(Imm32 imm, RegisterID dest) @@ -307,9 +342,9 @@ public: void swap(RegisterID reg1, RegisterID reg2) { - m_assembler.mov_r(ARM::S0, reg1); + m_assembler.mov_r(ARMRegisters::S0, reg1); m_assembler.mov_r(reg1, reg2); - m_assembler.mov_r(reg2, ARM::S0); + m_assembler.mov_r(reg2, ARMRegisters::S0); } void signExtend32ToPtr(RegisterID src, RegisterID dest) @@ -324,44 +359,50 @@ public: move(src, dest); } - Jump branch32(Condition cond, RegisterID left, RegisterID right) + Jump branch32(Condition cond, RegisterID left, RegisterID right, int useConstantPool = 0) { m_assembler.cmp_r(left, right); - return Jump(m_assembler.jmp(ARMCondition(cond))); + return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); } - Jump branch32(Condition cond, RegisterID left, Imm32 right) + Jump branch32(Condition cond, RegisterID left, Imm32 right, int useConstantPool = 0) { if (right.m_isPointer) { - m_assembler.ldr_un_imm(ARM::S0, right.m_value); - m_assembler.cmp_r(left, ARM::S0); + m_assembler.ldr_un_imm(ARMRegisters::S0, right.m_value); + m_assembler.cmp_r(left, ARMRegisters::S0); } else - m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARM::S0)); - return Jump(m_assembler.jmp(ARMCondition(cond))); + m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); + return Jump(m_assembler.jmp(ARMCondition(cond), useConstantPool)); } Jump branch32(Condition cond, RegisterID left, Address right) { - load32(right, ARM::S1); - return branch32(cond, left, ARM::S1); + load32(right, ARMRegisters::S1); + return branch32(cond, left, ARMRegisters::S1); } Jump branch32(Condition cond, Address left, RegisterID right) { - load32(left, ARM::S1); - return branch32(cond, ARM::S1, right); + load32(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); } Jump branch32(Condition cond, Address left, Imm32 right) { - load32(left, ARM::S1); - return branch32(cond, ARM::S1, right); + load32(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); } Jump branch32(Condition cond, BaseIndex left, Imm32 right) { - load32(left, ARM::S1); - return branch32(cond, ARM::S1, right); + load32(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); + } + + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + { + load32WithUnalignedHalfWords(left, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); } Jump branch16(Condition cond, BaseIndex left, RegisterID right) @@ -375,9 +416,9 @@ public: Jump branch16(Condition cond, BaseIndex left, Imm32 right) { - load16(left, ARM::S0); - move(right, ARM::S1); - m_assembler.cmp_r(ARM::S0, ARM::S1); + load16(left, ARMRegisters::S0); + move(right, ARMRegisters::S1); + m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S1); return m_assembler.jmp(ARMCondition(cond)); } @@ -391,9 +432,9 @@ public: Jump branchTest32(Condition cond, RegisterID reg, Imm32 mask = Imm32(-1)) { ASSERT((cond == Zero) || (cond == NonZero)); - ARMWord w = m_assembler.getImm(mask.m_value, ARM::S0, true); + ARMWord w = m_assembler.getImm(mask.m_value, ARMRegisters::S0, true); if (w & ARMAssembler::OP2_INV_IMM) - m_assembler.bics_r(ARM::S0, reg, w & ~ARMAssembler::OP2_INV_IMM); + m_assembler.bics_r(ARMRegisters::S0, reg, w & ~ARMAssembler::OP2_INV_IMM); else m_assembler.tst_r(reg, w); return Jump(m_assembler.jmp(ARMCondition(cond))); @@ -401,14 +442,14 @@ public: Jump branchTest32(Condition cond, Address address, Imm32 mask = Imm32(-1)) { - load32(address, ARM::S1); - return branchTest32(cond, ARM::S1, mask); + load32(address, ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); } Jump branchTest32(Condition cond, BaseIndex address, Imm32 mask = Imm32(-1)) { - load32(address, ARM::S1); - return branchTest32(cond, ARM::S1, mask); + load32(address, ARMRegisters::S1); + return branchTest32(cond, ARMRegisters::S1, mask); } Jump jump() @@ -418,12 +459,12 @@ public: void jump(RegisterID target) { - move(target, ARM::pc); + move(target, ARMRegisters::pc); } void jump(Address address) { - load32(address, ARM::pc); + load32(address, ARMRegisters::pc); } Jump branchAdd32(Condition cond, RegisterID src, RegisterID dest) @@ -443,11 +484,11 @@ public: void mull32(RegisterID src1, RegisterID src2, RegisterID dest) { if (src1 == dest) { - move(src1, ARM::S0); - src1 = ARM::S0; + move(src1, ARMRegisters::S0); + src1 = ARMRegisters::S0; } - m_assembler.mull_r(ARM::S1, dest, src2, src1); - m_assembler.cmp_r(ARM::S1, m_assembler.asr(dest, 31)); + m_assembler.mull_r(ARMRegisters::S1, dest, src2, src1); + m_assembler.cmp_r(ARMRegisters::S1, m_assembler.asr(dest, 31)); } Jump branchMul32(Condition cond, RegisterID src, RegisterID dest) @@ -466,8 +507,8 @@ public: { ASSERT((cond == Overflow) || (cond == Signed) || (cond == Zero) || (cond == NonZero)); if (cond == Overflow) { - move(imm, ARM::S0); - mull32(ARM::S0, src, dest); + move(imm, ARMRegisters::S0); + mull32(ARMRegisters::S0, src, dest); cond = NonZero; } else @@ -489,6 +530,13 @@ public: return Jump(m_assembler.jmp(ARMCondition(cond))); } + Jump branchOr32(Condition cond, RegisterID src, RegisterID dest) + { + ASSERT((cond == Signed) || (cond == Zero) || (cond == NonZero)); + or32(src, dest); + return Jump(m_assembler.jmp(ARMCondition(cond))); + } + void breakpoint() { m_assembler.bkpt(0); @@ -497,13 +545,13 @@ public: Call nearCall() { prepareCall(); - return Call(m_assembler.jmp(), Call::LinkableNear); + return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::LinkableNear); } Call call(RegisterID target) { prepareCall(); - move(ARM::pc, target); + move(ARMRegisters::pc, target); JmpSrc jmpSrc; return Call(jmpSrc, Call::None); } @@ -515,7 +563,7 @@ public: void ret() { - pop(ARM::pc); + m_assembler.mov_r(ARMRegisters::pc, linkRegister); } void set32(Condition cond, RegisterID left, RegisterID right, RegisterID dest) @@ -527,67 +575,92 @@ public: void set32(Condition cond, RegisterID left, Imm32 right, RegisterID dest) { - m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARM::S0)); + m_assembler.cmp_r(left, m_assembler.getImm(right.m_value, ARMRegisters::S0)); m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); } + void set8(Condition cond, RegisterID left, RegisterID right, RegisterID dest) + { + // ARM doesn't have byte registers + set32(cond, left, right, dest); + } + + void set8(Condition cond, Address left, RegisterID right, RegisterID dest) + { + // ARM doesn't have byte registers + load32(left, ARMRegisters::S1); + set32(cond, ARMRegisters::S1, right, dest); + } + + void set8(Condition cond, RegisterID left, Imm32 right, RegisterID dest) + { + // ARM doesn't have byte registers + set32(cond, left, right, dest); + } + void setTest32(Condition cond, Address address, Imm32 mask, RegisterID dest) { - load32(address, ARM::S1); + load32(address, ARMRegisters::S1); if (mask.m_value == -1) - m_assembler.cmp_r(0, ARM::S1); + m_assembler.cmp_r(0, ARMRegisters::S1); else - m_assembler.tst_r(ARM::S1, m_assembler.getImm(mask.m_value, ARM::S0)); + m_assembler.tst_r(ARMRegisters::S1, m_assembler.getImm(mask.m_value, ARMRegisters::S0)); m_assembler.mov_r(dest, ARMAssembler::getOp2(0)); m_assembler.mov_r(dest, ARMAssembler::getOp2(1), ARMCondition(cond)); } + void setTest8(Condition cond, Address address, Imm32 mask, RegisterID dest) + { + // ARM doesn't have byte registers + setTest32(cond, address, mask, dest); + } + void add32(Imm32 imm, RegisterID src, RegisterID dest) { - m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARM::S0)); + m_assembler.add_r(dest, src, m_assembler.getImm(imm.m_value, ARMRegisters::S0)); } void add32(Imm32 imm, AbsoluteAddress address) { - m_assembler.ldr_un_imm(ARM::S1, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(true, ARM::S1, ARM::S1, 0); - add32(imm, ARM::S1); - m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(false, ARM::S1, ARM::S0, 0); + m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); + m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); + add32(imm, ARMRegisters::S1); + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); + m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); } void sub32(Imm32 imm, AbsoluteAddress address) { - m_assembler.ldr_un_imm(ARM::S1, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(true, ARM::S1, ARM::S1, 0); - sub32(imm, ARM::S1); - m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address.m_ptr)); - m_assembler.dtr_u(false, ARM::S1, ARM::S0, 0); + m_assembler.ldr_un_imm(ARMRegisters::S1, reinterpret_cast<ARMWord>(address.m_ptr)); + m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); + sub32(imm, ARMRegisters::S1); + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address.m_ptr)); + m_assembler.dtr_u(false, ARMRegisters::S1, ARMRegisters::S0, 0); } void load32(void* address, RegisterID dest) { - m_assembler.ldr_un_imm(ARM::S0, reinterpret_cast<ARMWord>(address)); - m_assembler.dtr_u(true, dest, ARM::S0, 0); + m_assembler.ldr_un_imm(ARMRegisters::S0, reinterpret_cast<ARMWord>(address)); + m_assembler.dtr_u(true, dest, ARMRegisters::S0, 0); } Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) { - load32(left.m_ptr, ARM::S1); - return branch32(cond, ARM::S1, right); + load32(left.m_ptr, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); } Jump branch32(Condition cond, AbsoluteAddress left, Imm32 right) { - load32(left.m_ptr, ARM::S1); - return branch32(cond, ARM::S1, right); + load32(left.m_ptr, ARMRegisters::S1); + return branch32(cond, ARMRegisters::S1, right); } Call call() { prepareCall(); - return Call(m_assembler.jmp(), Call::Linkable); + return Call(m_assembler.jmp(ARMAssembler::AL, true), Call::Linkable); } Call tailRecursiveCall() @@ -609,25 +682,23 @@ public: Jump branchPtrWithPatch(Condition cond, RegisterID left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) { - dataLabel = moveWithPatch(initialRightValue, ARM::S1); - Jump jump = branch32(cond, left, ARM::S1); - jump.enableLatePatch(); + dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S1); + Jump jump = branch32(cond, left, ARMRegisters::S1, true); return jump; } Jump branchPtrWithPatch(Condition cond, Address left, DataLabelPtr& dataLabel, ImmPtr initialRightValue = ImmPtr(0)) { - load32(left, ARM::S1); - dataLabel = moveWithPatch(initialRightValue, ARM::S0); - Jump jump = branch32(cond, ARM::S0, ARM::S1); - jump.enableLatePatch(); + load32(left, ARMRegisters::S1); + dataLabel = moveWithPatch(initialRightValue, ARMRegisters::S0); + Jump jump = branch32(cond, ARMRegisters::S0, ARMRegisters::S1, true); return jump; } DataLabelPtr storePtrWithPatch(ImmPtr initialValue, ImplicitAddress address) { - DataLabelPtr dataLabel = moveWithPatch(initialValue, ARM::S1); - store32(ARM::S1, address); + DataLabelPtr dataLabel = moveWithPatch(initialValue, ARMRegisters::S1); + store32(ARMRegisters::S1, address); return dataLabel; } @@ -639,8 +710,7 @@ public: // Floating point operators bool supportsFloatingPoint() const { - // FIXME: should be a dynamic test: VFP, FPA, or nothing - return false; + return s_isVFPPresent; } bool supportsFloatingPointTruncate() const @@ -653,6 +723,12 @@ public: m_assembler.doubleTransfer(true, dest, address.base, address.offset); } + void loadDouble(void* address, FPRegisterID dest) + { + m_assembler.ldr_un_imm(ARMRegisters::S0, (ARMWord)address); + m_assembler.fdtr_u(true, dest, ARMRegisters::S0, 0); + } + void storeDouble(FPRegisterID src, ImplicitAddress address) { m_assembler.doubleTransfer(false, src, address.base, address.offset); @@ -665,8 +741,20 @@ public: void addDouble(Address src, FPRegisterID dest) { - loadDouble(src, ARM::SD0); - addDouble(ARM::SD0, dest); + loadDouble(src, ARMRegisters::SD0); + addDouble(ARMRegisters::SD0, dest); + } + + void divDouble(FPRegisterID src, FPRegisterID dest) + { + m_assembler.fdivd_r(dest, dest, src); + } + + void divDouble(Address src, FPRegisterID dest) + { + ASSERT_NOT_REACHED(); // Untested + loadDouble(src, ARMRegisters::SD0); + divDouble(ARMRegisters::SD0, dest); } void subDouble(FPRegisterID src, FPRegisterID dest) @@ -676,8 +764,8 @@ public: void subDouble(Address src, FPRegisterID dest) { - loadDouble(src, ARM::SD0); - subDouble(ARM::SD0, dest); + loadDouble(src, ARMRegisters::SD0); + subDouble(ARMRegisters::SD0, dest); } void mulDouble(FPRegisterID src, FPRegisterID dest) @@ -687,8 +775,8 @@ public: void mulDouble(Address src, FPRegisterID dest) { - loadDouble(src, ARM::SD0); - mulDouble(ARM::SD0, dest); + loadDouble(src, ARMRegisters::SD0); + mulDouble(ARMRegisters::SD0, dest); } void convertInt32ToDouble(RegisterID src, FPRegisterID dest) @@ -697,11 +785,30 @@ public: m_assembler.fsitod_r(dest, dest); } + void convertInt32ToDouble(Address src, FPRegisterID dest) + { + ASSERT_NOT_REACHED(); // Untested + // flds does not worth the effort here + load32(src, ARMRegisters::S1); + convertInt32ToDouble(ARMRegisters::S1, dest); + } + + void convertInt32ToDouble(AbsoluteAddress src, FPRegisterID dest) + { + ASSERT_NOT_REACHED(); // Untested + // flds does not worth the effort here + m_assembler.ldr_un_imm(ARMRegisters::S1, (ARMWord)src.m_ptr); + m_assembler.dtr_u(true, ARMRegisters::S1, ARMRegisters::S1, 0); + convertInt32ToDouble(ARMRegisters::S1, dest); + } + Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) { m_assembler.fcmpd_r(left, right); m_assembler.fmstat(); - return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond))); + if (cond & DoubleConditionBitSpecial) + m_assembler.cmp_r(ARMRegisters::S0, ARMRegisters::S0, ARMAssembler::VS); + return Jump(m_assembler.jmp(static_cast<ARMAssembler::Condition>(cond & ~DoubleConditionMask))); } // Truncates 'src' to an integer, and places the resulting 'dest'. @@ -716,52 +823,83 @@ public: return jump(); } + // Convert 'src' to an integer, and places the resulting 'dest'. + // If the result is not representable as a 32 bit value, branch. + // May also branch for some values that are representable in 32 bits + // (specifically, in this case, 0). + void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) + { + m_assembler.ftosid_r(ARMRegisters::SD0, src); + m_assembler.fmrs_r(dest, ARMRegisters::SD0); + + // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. + m_assembler.fsitod_r(ARMRegisters::SD0, ARMRegisters::SD0); + failureCases.append(branchDouble(DoubleNotEqualOrUnordered, src, ARMRegisters::SD0)); + + // If the result is zero, it might have been -0.0, and 0.0 equals to -0.0 + failureCases.append(branchTest32(Zero, dest)); + } + + void zeroDouble(FPRegisterID srcDest) + { + m_assembler.mov_r(ARMRegisters::S0, ARMAssembler::getOp2(0)); + convertInt32ToDouble(ARMRegisters::S0, srcDest); + } + protected: ARMAssembler::Condition ARMCondition(Condition cond) { return static_cast<ARMAssembler::Condition>(cond); } + void ensureSpace(int insnSpace, int constSpace) + { + m_assembler.ensureSpace(insnSpace, constSpace); + } + + int sizeOfConstantPool() + { + return m_assembler.sizeOfConstantPool(); + } + void prepareCall() { - m_assembler.ensureSpace(3 * sizeof(ARMWord), sizeof(ARMWord)); + ensureSpace(2 * sizeof(ARMWord), sizeof(ARMWord)); - // S0 might be used for parameter passing - m_assembler.add_r(ARM::S1, ARM::pc, ARMAssembler::OP2_IMM | 0x4); - m_assembler.push_r(ARM::S1); + m_assembler.mov_r(linkRegister, ARMRegisters::pc); } void call32(RegisterID base, int32_t offset) { - if (base == ARM::sp) + if (base == ARMRegisters::sp) offset += 4; if (offset >= 0) { if (offset <= 0xfff) { prepareCall(); - m_assembler.dtr_u(true, ARM::pc, base, offset); + m_assembler.dtr_u(true, ARMRegisters::pc, base, offset); } else if (offset <= 0xfffff) { - m_assembler.add_r(ARM::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.add_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); prepareCall(); - m_assembler.dtr_u(true, ARM::pc, ARM::S0, offset & 0xfff); + m_assembler.dtr_u(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff); } else { - ARMWord reg = m_assembler.getImm(offset, ARM::S0); + ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0); prepareCall(); - m_assembler.dtr_ur(true, ARM::pc, base, reg); + m_assembler.dtr_ur(true, ARMRegisters::pc, base, reg); } } else { offset = -offset; if (offset <= 0xfff) { prepareCall(); - m_assembler.dtr_d(true, ARM::pc, base, offset); + m_assembler.dtr_d(true, ARMRegisters::pc, base, offset); } else if (offset <= 0xfffff) { - m_assembler.sub_r(ARM::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); + m_assembler.sub_r(ARMRegisters::S0, base, ARMAssembler::OP2_IMM | (offset >> 12) | (10 << 8)); prepareCall(); - m_assembler.dtr_d(true, ARM::pc, ARM::S0, offset & 0xfff); + m_assembler.dtr_d(true, ARMRegisters::pc, ARMRegisters::S0, offset & 0xfff); } else { - ARMWord reg = m_assembler.getImm(offset, ARM::S0); + ARMWord reg = m_assembler.getImm(offset, ARMRegisters::S0); prepareCall(); - m_assembler.dtr_dr(true, ARM::pc, base, reg); + m_assembler.dtr_dr(true, ARMRegisters::pc, base, reg); } } } @@ -785,10 +923,11 @@ private: ARMAssembler::relinkCall(call.dataLocation(), destination.executableAddress()); } + static const bool s_isVFPPresent; }; } -#endif +#endif // ENABLE(ASSEMBLER) && PLATFORM(ARM_TRADITIONAL) #endif // MacroAssemblerARM_h diff --git a/JavaScriptCore/assembler/MacroAssemblerARMv7.h b/JavaScriptCore/assembler/MacroAssemblerARMv7.h index f7a8402..532a9cf 100644 --- a/JavaScriptCore/assembler/MacroAssemblerARMv7.h +++ b/JavaScriptCore/assembler/MacroAssemblerARMv7.h @@ -39,9 +39,9 @@ class MacroAssemblerARMv7 : public AbstractMacroAssembler<ARMv7Assembler> { // FIXME: switch dataTempRegister & addressTempRegister, or possibly use r7? // - dTR is likely used more than aTR, and we'll get better instruction // encoding if it's in the low 8 registers. - static const ARM::RegisterID dataTempRegister = ARM::ip; - static const RegisterID addressTempRegister = ARM::r3; - static const FPRegisterID fpTempRegister = ARM::d7; + static const ARMRegisters::RegisterID dataTempRegister = ARMRegisters::ip; + static const RegisterID addressTempRegister = ARMRegisters::r3; + static const FPRegisterID fpTempRegister = ARMRegisters::d7; struct ArmAddress { enum AddressType { @@ -93,17 +93,25 @@ public: Zero = ARMv7Assembler::ConditionEQ, NonZero = ARMv7Assembler::ConditionNE }; - enum DoubleCondition { + // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. DoubleEqual = ARMv7Assembler::ConditionEQ, + DoubleNotEqual = ARMv7Assembler::ConditionVC, // Not the right flag! check for this & handle differently. DoubleGreaterThan = ARMv7Assembler::ConditionGT, DoubleGreaterThanOrEqual = ARMv7Assembler::ConditionGE, DoubleLessThan = ARMv7Assembler::ConditionLO, DoubleLessThanOrEqual = ARMv7Assembler::ConditionLS, + // If either operand is NaN, these conditions always evaluate to true. + DoubleEqualOrUnordered = ARMv7Assembler::ConditionVS, // Not the right flag! check for this & handle differently. + DoubleNotEqualOrUnordered = ARMv7Assembler::ConditionNE, + DoubleGreaterThanOrUnordered = ARMv7Assembler::ConditionHI, + DoubleGreaterThanOrEqualOrUnordered = ARMv7Assembler::ConditionHS, + DoubleLessThanOrUnordered = ARMv7Assembler::ConditionLT, + DoubleLessThanOrEqualOrUnordered = ARMv7Assembler::ConditionLE, }; - static const RegisterID stackPointerRegister = ARM::sp; - static const RegisterID linkRegister = ARM::lr; + static const RegisterID stackPointerRegister = ARMRegisters::sp; + static const RegisterID linkRegister = ARMRegisters::lr; // Integer arithmetic operations: // @@ -189,14 +197,19 @@ public: } } - void lshift32(Imm32 imm, RegisterID dest) + void lshift32(RegisterID shift_amount, RegisterID dest) { - m_assembler.lsl(dest, dest, imm.m_value); + // Clamp the shift to the range 0..31 + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); + ASSERT(armImm.isValid()); + m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); + + m_assembler.lsl(dest, dest, dataTempRegister); } - void lshift32(RegisterID shift_amount, RegisterID dest) + void lshift32(Imm32 imm, RegisterID dest) { - m_assembler.lsl(dest, dest, shift_amount); + m_assembler.lsl(dest, dest, imm.m_value & 0x1f); } void mul32(RegisterID src, RegisterID dest) @@ -233,12 +246,17 @@ public: void rshift32(RegisterID shift_amount, RegisterID dest) { - m_assembler.asr(dest, dest, shift_amount); + // Clamp the shift to the range 0..31 + ARMThumbImmediate armImm = ARMThumbImmediate::makeEncodedImm(0x1f); + ASSERT(armImm.isValid()); + m_assembler.ARM_and(dataTempRegister, shift_amount, armImm); + + m_assembler.asr(dest, dest, dataTempRegister); } void rshift32(Imm32 imm, RegisterID dest) { - m_assembler.asr(dest, dest, imm.m_value); + m_assembler.asr(dest, dest, imm.m_value & 0x1f); } void sub32(RegisterID src, RegisterID dest) @@ -375,6 +393,11 @@ public: load32(setupArmAddress(address), dest); } + void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) + { + load32(setupArmAddress(address), dest); + } + void load32(void* address, RegisterID dest) { move(ImmPtr(address), addressTempRegister); @@ -526,12 +549,30 @@ public: { m_assembler.vcmp_F64(left, right); m_assembler.vmrs_APSR_nzcv_FPSCR(); + + if (cond == DoubleNotEqual) { + // ConditionNE jumps if NotEqual *or* unordered - force the unordered cases not to jump. + Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); + Jump result = makeBranch(ARMv7Assembler::ConditionNE); + unordered.link(this); + return result; + } + if (cond == DoubleEqualOrUnordered) { + Jump unordered = makeBranch(ARMv7Assembler::ConditionVS); + Jump notEqual = makeBranch(ARMv7Assembler::ConditionNE); + unordered.link(this); + // We get here if either unordered, or equal. + Jump result = makeJump(); + notEqual.link(this); + return result; + } return makeBranch(cond); } Jump branchTruncateDoubleToInt32(FPRegisterID, RegisterID) { ASSERT_NOT_REACHED(); + return jump(); } @@ -546,13 +587,13 @@ public: void pop(RegisterID dest) { // store postindexed with writeback - m_assembler.ldr(dest, ARM::sp, sizeof(void*), false, true); + m_assembler.ldr(dest, ARMRegisters::sp, sizeof(void*), false, true); } void push(RegisterID src) { // store preindexed with writeback - m_assembler.str(src, ARM::sp, -sizeof(void*), true, true); + m_assembler.str(src, ARMRegisters::sp, -sizeof(void*), true, true); } void push(Address address) @@ -716,6 +757,13 @@ public: return branch32(cond, addressTempRegister, right); } + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + { + // use addressTempRegister incase the branch32 we call uses dataTempRegister. :-/ + load32WithUnalignedHalfWords(left, addressTempRegister); + return branch32(cond, addressTempRegister, right); + } + Jump branch32(Condition cond, AbsoluteAddress left, RegisterID right) { load32(left.m_ptr, dataTempRegister); @@ -977,13 +1025,15 @@ public: protected: ARMv7Assembler::JmpSrc makeJump() { - return m_assembler.b(); + moveFixedWidthEncoding(Imm32(0), dataTempRegister); + return m_assembler.bx(dataTempRegister); } ARMv7Assembler::JmpSrc makeBranch(ARMv7Assembler::Condition cond) { - m_assembler.it(cond); - return m_assembler.b(); + m_assembler.it(cond, true, true); + moveFixedWidthEncoding(Imm32(0), dataTempRegister); + return m_assembler.bx(dataTempRegister); } ARMv7Assembler::JmpSrc makeBranch(Condition cond) { return makeBranch(armV7Condition(cond)); } ARMv7Assembler::JmpSrc makeBranch(DoubleCondition cond) { return makeBranch(armV7Condition(cond)); } @@ -1038,7 +1088,7 @@ protected: return addressTempRegister; } - DataLabel32 moveFixedWidthEncoding(Imm32 imm, RegisterID dst) + void moveFixedWidthEncoding(Imm32 imm, RegisterID dst) { uint32_t value = imm.m_value; m_assembler.movT3(dst, ARMThumbImmediate::makeUInt16(value & 0xffff)); diff --git a/JavaScriptCore/assembler/MacroAssemblerCodeRef.h b/JavaScriptCore/assembler/MacroAssemblerCodeRef.h index 341a7ff..3681af8 100644 --- a/JavaScriptCore/assembler/MacroAssemblerCodeRef.h +++ b/JavaScriptCore/assembler/MacroAssemblerCodeRef.h @@ -37,7 +37,7 @@ // ASSERT_VALID_CODE_POINTER checks that ptr is a non-null pointer, and that it is a valid // instruction address on the platform (for example, check any alignment requirements). -#if PLATFORM_ARM_ARCH(7) +#if PLATFORM(ARM_THUMB2) // ARM/thumb instructions must be 16-bit aligned, but all code pointers to be loaded // into the processor are decorated with the bottom bit set, indicating that this is // thumb code (as oposed to 32-bit traditional ARM). The first test checks for both @@ -69,7 +69,13 @@ public: template<typename FunctionType> explicit FunctionPtr(FunctionType* value) +#if COMPILER(RVCT) + // RVTC compiler needs C-style cast as it fails with the following error + // Error: #694: reinterpret_cast cannot cast away const or other type qualifiers + : m_value((void*)(value)) +#else : m_value(reinterpret_cast<void*>(value)) +#endif { ASSERT_VALID_CODE_POINTER(m_value); } @@ -124,7 +130,7 @@ public: } explicit MacroAssemblerCodePtr(void* value) -#if PLATFORM_ARM_ARCH(7) +#if PLATFORM(ARM_THUMB2) // Decorate the pointer as a thumb code pointer. : m_value(reinterpret_cast<char*>(value) + 1) #else @@ -141,7 +147,7 @@ public: } void* executableAddress() const { return m_value; } -#if PLATFORM_ARM_ARCH(7) +#if PLATFORM(ARM_THUMB2) // To use this pointer as a data address remove the decoration. void* dataLocation() const { ASSERT_VALID_CODE_POINTER(m_value); return reinterpret_cast<char*>(m_value) - 1; } #else diff --git a/JavaScriptCore/assembler/MacroAssemblerX86Common.h b/JavaScriptCore/assembler/MacroAssemblerX86Common.h index c9e3569..96d21f1 100644 --- a/JavaScriptCore/assembler/MacroAssemblerX86Common.h +++ b/JavaScriptCore/assembler/MacroAssemblerX86Common.h @@ -36,6 +36,10 @@ namespace JSC { class MacroAssemblerX86Common : public AbstractMacroAssembler<X86Assembler> { + static const int DoubleConditionBitInvert = 0x10; + static const int DoubleConditionBitSpecial = 0x20; + static const int DoubleConditionBits = DoubleConditionBitInvert | DoubleConditionBitSpecial; + public: enum Condition { @@ -56,15 +60,26 @@ public: }; enum DoubleCondition { - DoubleEqual = X86Assembler::ConditionE, + // These conditions will only evaluate to true if the comparison is ordered - i.e. neither operand is NaN. + DoubleEqual = X86Assembler::ConditionE | DoubleConditionBitSpecial, DoubleNotEqual = X86Assembler::ConditionNE, DoubleGreaterThan = X86Assembler::ConditionA, DoubleGreaterThanOrEqual = X86Assembler::ConditionAE, - DoubleLessThan = X86Assembler::ConditionB, - DoubleLessThanOrEqual = X86Assembler::ConditionBE, + DoubleLessThan = X86Assembler::ConditionA | DoubleConditionBitInvert, + DoubleLessThanOrEqual = X86Assembler::ConditionAE | DoubleConditionBitInvert, + // If either operand is NaN, these conditions always evaluate to true. + DoubleEqualOrUnordered = X86Assembler::ConditionE, + DoubleNotEqualOrUnordered = X86Assembler::ConditionNE | DoubleConditionBitSpecial, + DoubleGreaterThanOrUnordered = X86Assembler::ConditionB | DoubleConditionBitInvert, + DoubleGreaterThanOrEqualOrUnordered = X86Assembler::ConditionBE | DoubleConditionBitInvert, + DoubleLessThanOrUnordered = X86Assembler::ConditionB, + DoubleLessThanOrEqualOrUnordered = X86Assembler::ConditionBE, }; + COMPILE_ASSERT( + !((X86Assembler::ConditionE | X86Assembler::ConditionNE | X86Assembler::ConditionA | X86Assembler::ConditionAE | X86Assembler::ConditionB | X86Assembler::ConditionBE) & DoubleConditionBits), + DoubleConditionBits_should_not_interfere_with_X86Assembler_Condition_codes); - static const RegisterID stackPointerRegister = X86::esp; + static const RegisterID stackPointerRegister = X86Registers::esp; // Integer arithmetic operations: // @@ -132,20 +147,20 @@ public: { // On x86 we can only shift by ecx; if asked to shift by another register we'll // need rejig the shift amount into ecx first, and restore the registers afterwards. - if (shift_amount != X86::ecx) { - swap(shift_amount, X86::ecx); + if (shift_amount != X86Registers::ecx) { + swap(shift_amount, X86Registers::ecx); // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx" if (dest == shift_amount) - m_assembler.shll_CLr(X86::ecx); + m_assembler.shll_CLr(X86Registers::ecx); // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx" - else if (dest == X86::ecx) + else if (dest == X86Registers::ecx) m_assembler.shll_CLr(shift_amount); // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx" else m_assembler.shll_CLr(dest); - swap(shift_amount, X86::ecx); + swap(shift_amount, X86Registers::ecx); } else m_assembler.shll_CLr(dest); } @@ -214,20 +229,20 @@ public: { // On x86 we can only shift by ecx; if asked to shift by another register we'll // need rejig the shift amount into ecx first, and restore the registers afterwards. - if (shift_amount != X86::ecx) { - swap(shift_amount, X86::ecx); + if (shift_amount != X86Registers::ecx) { + swap(shift_amount, X86Registers::ecx); // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx" if (dest == shift_amount) - m_assembler.sarl_CLr(X86::ecx); + m_assembler.sarl_CLr(X86Registers::ecx); // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx" - else if (dest == X86::ecx) + else if (dest == X86Registers::ecx) m_assembler.sarl_CLr(shift_amount); // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx" else m_assembler.sarl_CLr(dest); - swap(shift_amount, X86::ecx); + swap(shift_amount, X86Registers::ecx); } else m_assembler.sarl_CLr(dest); } @@ -306,6 +321,11 @@ public: m_assembler.movl_mr(address.offset, address.base, address.index, address.scale, dest); } + void load32WithUnalignedHalfWords(BaseIndex address, RegisterID dest) + { + load32(address, dest); + } + DataLabel32 load32WithAddressOffsetPatch(Address address, RegisterID dest) { m_assembler.movl_mr_disp32(address.offset, address.base, dest); @@ -411,20 +431,35 @@ public: void convertInt32ToDouble(Address src, FPRegisterID dest) { + ASSERT(isSSE2Present()); m_assembler.cvtsi2sd_mr(src.offset, src.base, dest); } Jump branchDouble(DoubleCondition cond, FPRegisterID left, FPRegisterID right) { ASSERT(isSSE2Present()); - m_assembler.ucomisd_rr(right, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } - Jump branchDouble(DoubleCondition cond, FPRegisterID left, Address right) - { - m_assembler.ucomisd_mr(right.offset, right.base, left); - return Jump(m_assembler.jCC(x86Condition(cond))); + if (cond & DoubleConditionBitInvert) + m_assembler.ucomisd_rr(left, right); + else + m_assembler.ucomisd_rr(right, left); + + if (cond == DoubleEqual) { + Jump isUnordered(m_assembler.jp()); + Jump result = Jump(m_assembler.je()); + isUnordered.link(this); + return result; + } else if (cond == DoubleNotEqualOrUnordered) { + Jump isUnordered(m_assembler.jp()); + Jump isEqual(m_assembler.je()); + isUnordered.link(this); + Jump result = jump(); + isEqual.link(this); + return result; + } + + ASSERT(!(cond & DoubleConditionBitSpecial)); + return Jump(m_assembler.jCC(static_cast<X86Assembler::Condition>(cond & ~DoubleConditionBits))); } // Truncates 'src' to an integer, and places the resulting 'dest'. @@ -438,6 +473,25 @@ public: return branch32(Equal, dest, Imm32(0x80000000)); } + // Convert 'src' to an integer, and places the resulting 'dest'. + // If the result is not representable as a 32 bit value, branch. + // May also branch for some values that are representable in 32 bits + // (specifically, in this case, 0). + void branchConvertDoubleToInt32(FPRegisterID src, RegisterID dest, JumpList& failureCases, FPRegisterID fpTemp) + { + ASSERT(isSSE2Present()); + m_assembler.cvttsd2si_rr(src, dest); + + // If the result is zero, it might have been -0.0, and the double comparison won't catch this! + failureCases.append(branchTest32(Zero, dest)); + + // Convert the integer result back to float & compare to the original value - if not equal or unordered (NaN) then jump. + convertInt32ToDouble(dest, fpTemp); + m_assembler.ucomisd_rr(fpTemp, src); + failureCases.append(m_assembler.jp()); + failureCases.append(m_assembler.jne()); + } + void zeroDouble(FPRegisterID srcDest) { ASSERT(isSSE2Present()); @@ -499,15 +553,13 @@ public: void move(ImmPtr imm, RegisterID dest) { - if (CAN_SIGN_EXTEND_U32_64(imm.asIntptr())) - m_assembler.movl_i32r(static_cast<int32_t>(imm.asIntptr()), dest); - else - m_assembler.movq_i64r(imm.asIntptr(), dest); + m_assembler.movq_i64r(imm.asIntptr(), dest); } void swap(RegisterID reg1, RegisterID reg2) { - m_assembler.xchgq_rr(reg1, reg2); + if (reg1 != reg2) + m_assembler.xchgq_rr(reg1, reg2); } void signExtend32ToPtr(RegisterID src, RegisterID dest) @@ -607,6 +659,11 @@ public: return Jump(m_assembler.jCC(x86Condition(cond))); } + Jump branch32WithUnalignedHalfWords(Condition cond, BaseIndex left, Imm32 right) + { + return branch32(cond, left, right); + } + Jump branch16(Condition cond, BaseIndex left, RegisterID right) { m_assembler.cmpw_rm(right, left.offset, left.base, left.index, left.scale); @@ -882,11 +939,6 @@ protected: return static_cast<X86Assembler::Condition>(cond); } - X86Assembler::Condition x86Condition(DoubleCondition cond) - { - return static_cast<X86Assembler::Condition>(cond); - } - private: // Only MacroAssemblerX86 should be using the following method; SSE2 is always available on // x86_64, and clients & subclasses of MacroAssembler should be using 'supportsFloatingPoint()'. diff --git a/JavaScriptCore/assembler/MacroAssemblerX86_64.h b/JavaScriptCore/assembler/MacroAssemblerX86_64.h index e3d296c..7828cf5 100644 --- a/JavaScriptCore/assembler/MacroAssemblerX86_64.h +++ b/JavaScriptCore/assembler/MacroAssemblerX86_64.h @@ -38,7 +38,7 @@ namespace JSC { class MacroAssemblerX86_64 : public MacroAssemblerX86Common { protected: - static const X86::RegisterID scratchRegister = X86::r11; + static const X86Registers::RegisterID scratchRegister = X86Registers::r11; public: static const Scale ScalePtr = TimesEight; @@ -79,12 +79,12 @@ public: void load32(void* address, RegisterID dest) { - if (dest == X86::eax) + if (dest == X86Registers::eax) m_assembler.movl_mEAX(address); else { - move(X86::eax, dest); + move(X86Registers::eax, dest); m_assembler.movl_mEAX(address); - swap(X86::eax, dest); + swap(X86Registers::eax, dest); } } @@ -102,10 +102,10 @@ public: void store32(Imm32 imm, void* address) { - move(X86::eax, scratchRegister); - move(imm, X86::eax); + move(X86Registers::eax, scratchRegister); + move(imm, X86Registers::eax); m_assembler.movl_EAXm(address); - move(scratchRegister, X86::eax); + move(scratchRegister, X86Registers::eax); } Call call() @@ -192,33 +192,6 @@ public: m_assembler.orq_ir(imm.m_value, dest); } - void rshiftPtr(RegisterID shift_amount, RegisterID dest) - { - // On x86 we can only shift by ecx; if asked to shift by another register we'll - // need rejig the shift amount into ecx first, and restore the registers afterwards. - if (shift_amount != X86::ecx) { - swap(shift_amount, X86::ecx); - - // E.g. transform "shll %eax, %eax" -> "xchgl %eax, %ecx; shll %ecx, %ecx; xchgl %eax, %ecx" - if (dest == shift_amount) - m_assembler.sarq_CLr(X86::ecx); - // E.g. transform "shll %eax, %ecx" -> "xchgl %eax, %ecx; shll %ecx, %eax; xchgl %eax, %ecx" - else if (dest == X86::ecx) - m_assembler.sarq_CLr(shift_amount); - // E.g. transform "shll %eax, %ebx" -> "xchgl %eax, %ecx; shll %ecx, %ebx; xchgl %eax, %ecx" - else - m_assembler.sarq_CLr(dest); - - swap(shift_amount, X86::ecx); - } else - m_assembler.sarq_CLr(dest); - } - - void rshiftPtr(Imm32 imm, RegisterID dest) - { - m_assembler.sarq_i8r(imm.m_value, dest); - } - void subPtr(RegisterID src, RegisterID dest) { m_assembler.subq_rr(src, dest); @@ -258,12 +231,12 @@ public: void loadPtr(void* address, RegisterID dest) { - if (dest == X86::eax) + if (dest == X86Registers::eax) m_assembler.movq_mEAX(address); else { - move(X86::eax, dest); + move(X86Registers::eax, dest); m_assembler.movq_mEAX(address); - swap(X86::eax, dest); + swap(X86Registers::eax, dest); } } @@ -285,24 +258,19 @@ public: void storePtr(RegisterID src, void* address) { - if (src == X86::eax) + if (src == X86Registers::eax) m_assembler.movq_EAXm(address); else { - swap(X86::eax, src); + swap(X86Registers::eax, src); m_assembler.movq_EAXm(address); - swap(X86::eax, src); + swap(X86Registers::eax, src); } } void storePtr(ImmPtr imm, ImplicitAddress address) { - intptr_t ptr = imm.asIntptr(); - if (CAN_SIGN_EXTEND_32_64(ptr)) - m_assembler.movq_i32m(static_cast<int>(ptr), address.offset, address.base); - else { - move(imm, scratchRegister); - storePtr(scratchRegister, address); - } + move(imm, scratchRegister); + storePtr(scratchRegister, address); } DataLabel32 storePtrWithAddressOffsetPatch(RegisterID src, Address address) @@ -339,17 +307,8 @@ public: Jump branchPtr(Condition cond, RegisterID left, ImmPtr right) { - intptr_t imm = right.asIntptr(); - if (CAN_SIGN_EXTEND_32_64(imm)) { - if (!imm) - m_assembler.testq_rr(left, left); - else - m_assembler.cmpq_ir(imm, left); - return Jump(m_assembler.jCC(x86Condition(cond))); - } else { - move(right, scratchRegister); - return branchPtr(cond, left, scratchRegister); - } + move(right, scratchRegister); + return branchPtr(cond, left, scratchRegister); } Jump branchPtr(Condition cond, RegisterID left, Address right) diff --git a/JavaScriptCore/assembler/X86Assembler.h b/JavaScriptCore/assembler/X86Assembler.h index fb58361..cbbaaa5 100644 --- a/JavaScriptCore/assembler/X86Assembler.h +++ b/JavaScriptCore/assembler/X86Assembler.h @@ -38,12 +38,8 @@ namespace JSC { inline bool CAN_SIGN_EXTEND_8_32(int32_t value) { return value == (int32_t)(signed char)value; } -#if PLATFORM(X86_64) -inline bool CAN_SIGN_EXTEND_32_64(intptr_t value) { return value == (intptr_t)(int32_t)value; } -inline bool CAN_SIGN_EXTEND_U32_64(intptr_t value) { return value == (intptr_t)(uint32_t)value; } -#endif -namespace X86 { +namespace X86Registers { typedef enum { eax, ecx, @@ -80,8 +76,8 @@ namespace X86 { class X86Assembler { public: - typedef X86::RegisterID RegisterID; - typedef X86::XMMRegisterID XMMRegisterID; + typedef X86Registers::RegisterID RegisterID; + typedef X86Registers::XMMRegisterID XMMRegisterID; typedef XMMRegisterID FPRegisterID; typedef enum { @@ -231,7 +227,6 @@ public: { } - void enableLatePatch() { } private: JmpSrc(int offset) : m_offset(offset) @@ -1119,7 +1114,7 @@ public: #else void movl_rm(RegisterID src, void* addr) { - if (src == X86::eax) + if (src == X86Registers::eax) movl_EAXm(addr); else m_formatter.oneByteOp(OP_MOV_EvGv, src, addr); @@ -1127,7 +1122,7 @@ public: void movl_mr(void* addr, RegisterID dst) { - if (dst == X86::eax) + if (dst == X86Registers::eax) movl_mEAX(addr); else m_formatter.oneByteOp(OP_MOV_GvEv, dst, addr); @@ -1893,23 +1888,23 @@ private: // Internals; ModRm and REX formatters. - static const RegisterID noBase = X86::ebp; - static const RegisterID hasSib = X86::esp; - static const RegisterID noIndex = X86::esp; + static const RegisterID noBase = X86Registers::ebp; + static const RegisterID hasSib = X86Registers::esp; + static const RegisterID noIndex = X86Registers::esp; #if PLATFORM(X86_64) - static const RegisterID noBase2 = X86::r13; - static const RegisterID hasSib2 = X86::r12; + static const RegisterID noBase2 = X86Registers::r13; + static const RegisterID hasSib2 = X86Registers::r12; // Registers r8 & above require a REX prefixe. inline bool regRequiresRex(int reg) { - return (reg >= X86::r8); + return (reg >= X86Registers::r8); } // Byte operand register spl & above require a REX prefix (to prevent the 'H' registers be accessed). inline bool byteRegRequiresRex(int reg) { - return (reg >= X86::esp); + return (reg >= X86Registers::esp); } // Format a REX prefix byte. diff --git a/JavaScriptCore/bytecode/CodeBlock.cpp b/JavaScriptCore/bytecode/CodeBlock.cpp index e22f25a..13bed8c 100644 --- a/JavaScriptCore/bytecode/CodeBlock.cpp +++ b/JavaScriptCore/bytecode/CodeBlock.cpp @@ -33,6 +33,8 @@ #include "JIT.h" #include "JSValue.h" #include "Interpreter.h" +#include "JSFunction.h" +#include "JSStaticScopeObject.h" #include "Debugger.h" #include "BytecodeGenerator.h" #include <stdio.h> @@ -69,17 +71,9 @@ static UString valueToSourceString(ExecState* exec, JSValue val) return val.toString(exec); } -static CString registerName(int r) -{ - if (r == missingThisObjectMarker()) - return "<null>"; - - return (UString("r") + UString::from(r)).UTF8String(); -} - static CString constantName(ExecState* exec, int k, JSValue value) { - return (valueToSourceString(exec, value) + "(@k" + UString::from(k) + ")").UTF8String(); + return (valueToSourceString(exec, value) + "(@k" + UString::from(k - FirstConstantRegisterIndex) + ")").UTF8String(); } static CString idName(int id0, const Identifier& ident) @@ -87,6 +81,17 @@ static CString idName(int id0, const Identifier& ident) return (ident.ustring() + "(@id" + UString::from(id0) +")").UTF8String(); } +CString CodeBlock::registerName(ExecState* exec, int r) const +{ + if (r == missingThisObjectMarker()) + return "<null>"; + + if (isConstantRegisterIndex(r)) + return constantName(exec, r, getConstant(r)); + + return (UString("r") + UString::from(r)).UTF8String(); +} + static UString regexpToSourceString(RegExp* regExp) { UString pattern = UString("/") + regExp->pattern() + "/"; @@ -133,49 +138,44 @@ NEVER_INLINE static const char* debugHookName(int debugHookID) return ""; } -static int locationForOffset(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int offset) -{ - return it - begin + offset; -} - -static void printUnaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op) +void CodeBlock::printUnaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str()); + printf("[%4d] %s\t\t %s, %s\n", location, op, registerName(exec, r0).c_str(), registerName(exec, r1).c_str()); } -static void printBinaryOp(int location, Vector<Instruction>::const_iterator& it, const char* op) +void CodeBlock::printBinaryOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str()); + printf("[%4d] %s\t\t %s, %s, %s\n", location, op, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), registerName(exec, r2).c_str()); } -static void printConditionalJump(const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator& it, int location, const char* op) +void CodeBlock::printConditionalJump(ExecState* exec, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator& it, int location, const char* op) const { int r0 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(r0).c_str(), offset, locationForOffset(begin, it, offset)); + printf("[%4d] %s\t\t %s, %d(->%d)\n", location, op, registerName(exec, r0).c_str(), offset, location + offset); } -static void printGetByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op) +void CodeBlock::printGetByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; - printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str()); + printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), idName(id0, m_identifiers[id0]).c_str()); it += 4; } -static void printPutByIdOp(int location, Vector<Instruction>::const_iterator& it, const Vector<Identifier>& m_identifiers, const char* op) +void CodeBlock::printPutByIdOp(ExecState* exec, int location, Vector<Instruction>::const_iterator& it, const char* op) const { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str()); + printf("[%4d] %s\t %s, %s, %s\n", location, op, registerName(exec, r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(exec, r1).c_str()); it += 4; } @@ -360,7 +360,7 @@ void CodeBlock::dump(ExecState* exec) const unsigned registerIndex = m_numVars; size_t i = 0; do { - printf(" r%u = %s\n", registerIndex, valueToSourceString(exec, m_constantRegisters[i].jsValue()).ascii()); + printf(" k%u = %s\n", registerIndex, valueToSourceString(exec, m_constantRegisters[i].jsValue()).ascii()); ++i; ++registerIndex; } while (i < m_constantRegisters.size()); @@ -484,7 +484,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_enter_with_activation: { int r0 = (++it)->u.operand; - printf("[%4d] enter_with_activation %s\n", location, registerName(r0).c_str()); + printf("[%4d] enter_with_activation %s\n", location, registerName(exec, r0).c_str()); break; } case op_create_arguments: { @@ -497,148 +497,148 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_convert_this: { int r0 = (++it)->u.operand; - printf("[%4d] convert_this %s\n", location, registerName(r0).c_str()); + printf("[%4d] convert_this %s\n", location, registerName(exec, r0).c_str()); break; } case op_new_object: { int r0 = (++it)->u.operand; - printf("[%4d] new_object\t %s\n", location, registerName(r0).c_str()); + printf("[%4d] new_object\t %s\n", location, registerName(exec, r0).c_str()); break; } case op_new_array: { int dst = (++it)->u.operand; int argv = (++it)->u.operand; int argc = (++it)->u.operand; - printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(dst).c_str(), registerName(argv).c_str(), argc); + printf("[%4d] new_array\t %s, %s, %d\n", location, registerName(exec, dst).c_str(), registerName(exec, argv).c_str(), argc); break; } case op_new_regexp: { int r0 = (++it)->u.operand; int re0 = (++it)->u.operand; - printf("[%4d] new_regexp\t %s, %s\n", location, registerName(r0).c_str(), regexpName(re0, regexp(re0)).c_str()); + printf("[%4d] new_regexp\t %s, %s\n", location, registerName(exec, r0).c_str(), regexpName(re0, regexp(re0)).c_str()); break; } case op_mov: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] mov\t\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str()); + printf("[%4d] mov\t\t %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str()); break; } case op_not: { - printUnaryOp(location, it, "not"); + printUnaryOp(exec, location, it, "not"); break; } case op_eq: { - printBinaryOp(location, it, "eq"); + printBinaryOp(exec, location, it, "eq"); break; } case op_eq_null: { - printUnaryOp(location, it, "eq_null"); + printUnaryOp(exec, location, it, "eq_null"); break; } case op_neq: { - printBinaryOp(location, it, "neq"); + printBinaryOp(exec, location, it, "neq"); break; } case op_neq_null: { - printUnaryOp(location, it, "neq_null"); + printUnaryOp(exec, location, it, "neq_null"); break; } case op_stricteq: { - printBinaryOp(location, it, "stricteq"); + printBinaryOp(exec, location, it, "stricteq"); break; } case op_nstricteq: { - printBinaryOp(location, it, "nstricteq"); + printBinaryOp(exec, location, it, "nstricteq"); break; } case op_less: { - printBinaryOp(location, it, "less"); + printBinaryOp(exec, location, it, "less"); break; } case op_lesseq: { - printBinaryOp(location, it, "lesseq"); + printBinaryOp(exec, location, it, "lesseq"); break; } case op_pre_inc: { int r0 = (++it)->u.operand; - printf("[%4d] pre_inc\t\t %s\n", location, registerName(r0).c_str()); + printf("[%4d] pre_inc\t\t %s\n", location, registerName(exec, r0).c_str()); break; } case op_pre_dec: { int r0 = (++it)->u.operand; - printf("[%4d] pre_dec\t\t %s\n", location, registerName(r0).c_str()); + printf("[%4d] pre_dec\t\t %s\n", location, registerName(exec, r0).c_str()); break; } case op_post_inc: { - printUnaryOp(location, it, "post_inc"); + printUnaryOp(exec, location, it, "post_inc"); break; } case op_post_dec: { - printUnaryOp(location, it, "post_dec"); + printUnaryOp(exec, location, it, "post_dec"); break; } case op_to_jsnumber: { - printUnaryOp(location, it, "to_jsnumber"); + printUnaryOp(exec, location, it, "to_jsnumber"); break; } case op_negate: { - printUnaryOp(location, it, "negate"); + printUnaryOp(exec, location, it, "negate"); break; } case op_add: { - printBinaryOp(location, it, "add"); + printBinaryOp(exec, location, it, "add"); ++it; break; } case op_mul: { - printBinaryOp(location, it, "mul"); + printBinaryOp(exec, location, it, "mul"); ++it; break; } case op_div: { - printBinaryOp(location, it, "div"); + printBinaryOp(exec, location, it, "div"); ++it; break; } case op_mod: { - printBinaryOp(location, it, "mod"); + printBinaryOp(exec, location, it, "mod"); break; } case op_sub: { - printBinaryOp(location, it, "sub"); + printBinaryOp(exec, location, it, "sub"); ++it; break; } case op_lshift: { - printBinaryOp(location, it, "lshift"); + printBinaryOp(exec, location, it, "lshift"); break; } case op_rshift: { - printBinaryOp(location, it, "rshift"); + printBinaryOp(exec, location, it, "rshift"); break; } case op_urshift: { - printBinaryOp(location, it, "urshift"); + printBinaryOp(exec, location, it, "urshift"); break; } case op_bitand: { - printBinaryOp(location, it, "bitand"); + printBinaryOp(exec, location, it, "bitand"); ++it; break; } case op_bitxor: { - printBinaryOp(location, it, "bitxor"); + printBinaryOp(exec, location, it, "bitxor"); ++it; break; } case op_bitor: { - printBinaryOp(location, it, "bitor"); + printBinaryOp(exec, location, it, "bitor"); ++it; break; } case op_bitnot: { - printUnaryOp(location, it, "bitnot"); + printUnaryOp(exec, location, it, "bitnot"); break; } case op_instanceof: { @@ -646,59 +646,59 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; int r3 = (++it)->u.operand; - printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str(), registerName(r3).c_str()); + printf("[%4d] instanceof\t\t %s, %s, %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), registerName(exec, r2).c_str(), registerName(exec, r3).c_str()); break; } case op_typeof: { - printUnaryOp(location, it, "typeof"); + printUnaryOp(exec, location, it, "typeof"); break; } case op_is_undefined: { - printUnaryOp(location, it, "is_undefined"); + printUnaryOp(exec, location, it, "is_undefined"); break; } case op_is_boolean: { - printUnaryOp(location, it, "is_boolean"); + printUnaryOp(exec, location, it, "is_boolean"); break; } case op_is_number: { - printUnaryOp(location, it, "is_number"); + printUnaryOp(exec, location, it, "is_number"); break; } case op_is_string: { - printUnaryOp(location, it, "is_string"); + printUnaryOp(exec, location, it, "is_string"); break; } case op_is_object: { - printUnaryOp(location, it, "is_object"); + printUnaryOp(exec, location, it, "is_object"); break; } case op_is_function: { - printUnaryOp(location, it, "is_function"); + printUnaryOp(exec, location, it, "is_function"); break; } case op_in: { - printBinaryOp(location, it, "in"); + printBinaryOp(exec, location, it, "in"); break; } case op_resolve: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; - printf("[%4d] resolve\t\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str()); + printf("[%4d] resolve\t\t %s, %s\n", location, registerName(exec, r0).c_str(), idName(id0, m_identifiers[id0]).c_str()); break; } case op_resolve_skip: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int skipLevels = (++it)->u.operand; - printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), skipLevels); + printf("[%4d] resolve_skip\t %s, %s, %d\n", location, registerName(exec, r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), skipLevels); break; } case op_resolve_global: { int r0 = (++it)->u.operand; JSValue scope = JSValue((++it)->u.jsCell); int id0 = (++it)->u.operand; - printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), idName(id0, m_identifiers[id0]).c_str()); + printf("[%4d] resolve_global\t %s, %s, %s\n", location, registerName(exec, r0).c_str(), valueToSourceString(exec, scope).ascii(), idName(id0, m_identifiers[id0]).c_str()); it += 2; break; } @@ -706,244 +706,265 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int index = (++it)->u.operand; int skipLevels = (++it)->u.operand; - printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(r0).c_str(), index, skipLevels); + printf("[%4d] get_scoped_var\t %s, %d, %d\n", location, registerName(exec, r0).c_str(), index, skipLevels); break; } case op_put_scoped_var: { int index = (++it)->u.operand; int skipLevels = (++it)->u.operand; int r0 = (++it)->u.operand; - printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(r0).c_str()); + printf("[%4d] put_scoped_var\t %d, %d, %s\n", location, index, skipLevels, registerName(exec, r0).c_str()); break; } case op_get_global_var: { int r0 = (++it)->u.operand; JSValue scope = JSValue((++it)->u.jsCell); int index = (++it)->u.operand; - printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(r0).c_str(), valueToSourceString(exec, scope).ascii(), index); + printf("[%4d] get_global_var\t %s, %s, %d\n", location, registerName(exec, r0).c_str(), valueToSourceString(exec, scope).ascii(), index); break; } case op_put_global_var: { JSValue scope = JSValue((++it)->u.jsCell); int index = (++it)->u.operand; int r0 = (++it)->u.operand; - printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).ascii(), index, registerName(r0).c_str()); + printf("[%4d] put_global_var\t %s, %d, %s\n", location, valueToSourceString(exec, scope).ascii(), index, registerName(exec, r0).c_str()); break; } case op_resolve_base: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; - printf("[%4d] resolve_base\t %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str()); + printf("[%4d] resolve_base\t %s, %s\n", location, registerName(exec, r0).c_str(), idName(id0, m_identifiers[id0]).c_str()); break; } case op_resolve_with_base: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; - printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str()); + printf("[%4d] resolve_with_base %s, %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), idName(id0, m_identifiers[id0]).c_str()); break; } case op_get_by_id: { - printGetByIdOp(location, it, m_identifiers, "get_by_id"); + printGetByIdOp(exec, location, it, "get_by_id"); break; } case op_get_by_id_self: { - printGetByIdOp(location, it, m_identifiers, "get_by_id_self"); + printGetByIdOp(exec, location, it, "get_by_id_self"); break; } case op_get_by_id_self_list: { - printGetByIdOp(location, it, m_identifiers, "get_by_id_self_list"); + printGetByIdOp(exec, location, it, "get_by_id_self_list"); break; } case op_get_by_id_proto: { - printGetByIdOp(location, it, m_identifiers, "get_by_id_proto"); + printGetByIdOp(exec, location, it, "get_by_id_proto"); break; } case op_get_by_id_proto_list: { - printGetByIdOp(location, it, m_identifiers, "op_get_by_id_proto_list"); + printGetByIdOp(exec, location, it, "op_get_by_id_proto_list"); break; } case op_get_by_id_chain: { - printGetByIdOp(location, it, m_identifiers, "get_by_id_chain"); + printGetByIdOp(exec, location, it, "get_by_id_chain"); break; } case op_get_by_id_generic: { - printGetByIdOp(location, it, m_identifiers, "get_by_id_generic"); + printGetByIdOp(exec, location, it, "get_by_id_generic"); break; } case op_get_array_length: { - printGetByIdOp(location, it, m_identifiers, "get_array_length"); + printGetByIdOp(exec, location, it, "get_array_length"); break; } case op_get_string_length: { - printGetByIdOp(location, it, m_identifiers, "get_string_length"); + printGetByIdOp(exec, location, it, "get_string_length"); break; } case op_put_by_id: { - printPutByIdOp(location, it, m_identifiers, "put_by_id"); + printPutByIdOp(exec, location, it, "put_by_id"); break; } case op_put_by_id_replace: { - printPutByIdOp(location, it, m_identifiers, "put_by_id_replace"); + printPutByIdOp(exec, location, it, "put_by_id_replace"); break; } case op_put_by_id_transition: { - printPutByIdOp(location, it, m_identifiers, "put_by_id_transition"); + printPutByIdOp(exec, location, it, "put_by_id_transition"); break; } case op_put_by_id_generic: { - printPutByIdOp(location, it, m_identifiers, "put_by_id_generic"); + printPutByIdOp(exec, location, it, "put_by_id_generic"); break; } case op_put_getter: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str()); + printf("[%4d] put_getter\t %s, %s, %s\n", location, registerName(exec, r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(exec, r1).c_str()); break; } case op_put_setter: { int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str()); + printf("[%4d] put_setter\t %s, %s, %s\n", location, registerName(exec, r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(exec, r1).c_str()); break; } case op_method_check: { - printf("[%4d] op_method_check\n", location); + printf("[%4d] method_check\n", location); break; } case op_del_by_id: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int id0 = (++it)->u.operand; - printf("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), idName(id0, m_identifiers[id0]).c_str()); + printf("[%4d] del_by_id\t %s, %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), idName(id0, m_identifiers[id0]).c_str()); break; } case op_get_by_val: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str()); + printf("[%4d] get_by_val\t %s, %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), registerName(exec, r2).c_str()); + break; + } + case op_get_by_pname: { + int r0 = (++it)->u.operand; + int r1 = (++it)->u.operand; + int r2 = (++it)->u.operand; + int r3 = (++it)->u.operand; + int r4 = (++it)->u.operand; + int r5 = (++it)->u.operand; + printf("[%4d] get_by_pname\t %s, %s, %s, %s, %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), registerName(exec, r2).c_str(), registerName(exec, r3).c_str(), registerName(exec, r4).c_str(), registerName(exec, r5).c_str()); break; } case op_put_by_val: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str()); + printf("[%4d] put_by_val\t %s, %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), registerName(exec, r2).c_str()); break; } case op_del_by_val: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int r2 = (++it)->u.operand; - printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str(), registerName(r2).c_str()); + printf("[%4d] del_by_val\t %s, %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), registerName(exec, r2).c_str()); break; } case op_put_by_index: { int r0 = (++it)->u.operand; unsigned n0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(r0).c_str(), n0, registerName(r1).c_str()); + printf("[%4d] put_by_index\t %s, %u, %s\n", location, registerName(exec, r0).c_str(), n0, registerName(exec, r1).c_str()); break; } case op_jmp: { int offset = (++it)->u.operand; - printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset)); + printf("[%4d] jmp\t\t %d(->%d)\n", location, offset, location + offset); break; } case op_loop: { int offset = (++it)->u.operand; - printf("[%4d] loop\t\t %d(->%d)\n", location, offset, locationForOffset(begin, it, offset)); + printf("[%4d] loop\t\t %d(->%d)\n", location, offset, location + offset); break; } case op_jtrue: { - printConditionalJump(begin, it, location, "jtrue"); + printConditionalJump(exec, begin, it, location, "jtrue"); break; } case op_loop_if_true: { - printConditionalJump(begin, it, location, "loop_if_true"); + printConditionalJump(exec, begin, it, location, "loop_if_true"); + break; + } + case op_loop_if_false: { + printConditionalJump(exec, begin, it, location, "loop_if_false"); break; } case op_jfalse: { - printConditionalJump(begin, it, location, "jfalse"); + printConditionalJump(exec, begin, it, location, "jfalse"); break; } case op_jeq_null: { - printConditionalJump(begin, it, location, "jeq_null"); + printConditionalJump(exec, begin, it, location, "jeq_null"); break; } case op_jneq_null: { - printConditionalJump(begin, it, location, "jneq_null"); + printConditionalJump(exec, begin, it, location, "jneq_null"); break; } case op_jneq_ptr: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset)); + printf("[%4d] jneq_ptr\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset); break; } case op_jnless: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset)); + printf("[%4d] jnless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset); break; } case op_jnlesseq: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset)); + printf("[%4d] jnlesseq\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset); break; } case op_loop_if_less: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset)); + printf("[%4d] loop_if_less\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset); + break; + } + case op_jless: { + int r0 = (++it)->u.operand; + int r1 = (++it)->u.operand; + int offset = (++it)->u.operand; + printf("[%4d] jless\t\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset); break; } case op_loop_if_lesseq: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(r0).c_str(), registerName(r1).c_str(), offset, locationForOffset(begin, it, offset)); + printf("[%4d] loop_if_lesseq\t %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), offset, location + offset); break; } case op_switch_imm: { int tableIndex = (++it)->u.operand; int defaultTarget = (++it)->u.operand; int scrutineeRegister = (++it)->u.operand; - printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str()); + printf("[%4d] switch_imm\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).c_str()); break; } case op_switch_char: { int tableIndex = (++it)->u.operand; int defaultTarget = (++it)->u.operand; int scrutineeRegister = (++it)->u.operand; - printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str()); + printf("[%4d] switch_char\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).c_str()); break; } case op_switch_string: { int tableIndex = (++it)->u.operand; int defaultTarget = (++it)->u.operand; int scrutineeRegister = (++it)->u.operand; - printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, locationForOffset(begin, it, defaultTarget), registerName(scrutineeRegister).c_str()); + printf("[%4d] switch_string\t %d, %d(->%d), %s\n", location, tableIndex, defaultTarget, location + defaultTarget, registerName(exec, scrutineeRegister).c_str()); break; } case op_new_func: { int r0 = (++it)->u.operand; int f0 = (++it)->u.operand; - printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(r0).c_str(), f0); + printf("[%4d] new_func\t\t %s, f%d\n", location, registerName(exec, r0).c_str(), f0); break; } case op_new_func_exp: { int r0 = (++it)->u.operand; int f0 = (++it)->u.operand; - printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(r0).c_str(), f0); + printf("[%4d] new_func_exp\t %s, f%d\n", location, registerName(exec, r0).c_str(), f0); break; } case op_call: { @@ -951,7 +972,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int func = (++it)->u.operand; int argCount = (++it)->u.operand; int registerOffset = (++it)->u.operand; - printf("[%4d] call\t\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset); + printf("[%4d] call\t\t %s, %s, %d, %d\n", location, registerName(exec, dst).c_str(), registerName(exec, func).c_str(), argCount, registerOffset); break; } case op_call_eval: { @@ -959,7 +980,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int func = (++it)->u.operand; int argCount = (++it)->u.operand; int registerOffset = (++it)->u.operand; - printf("[%4d] call_eval\t %s, %s, %d, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset); + printf("[%4d] call_eval\t %s, %s, %d, %d\n", location, registerName(exec, dst).c_str(), registerName(exec, func).c_str(), argCount, registerOffset); break; } case op_call_varargs: { @@ -967,16 +988,16 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int func = (++it)->u.operand; int argCount = (++it)->u.operand; int registerOffset = (++it)->u.operand; - printf("[%4d] call_varargs\t %s, %s, %s, %d\n", location, registerName(dst).c_str(), registerName(func).c_str(), registerName(argCount).c_str(), registerOffset); + printf("[%4d] call_varargs\t %s, %s, %s, %d\n", location, registerName(exec, dst).c_str(), registerName(exec, func).c_str(), registerName(exec, argCount).c_str(), registerOffset); break; } case op_load_varargs: { - printUnaryOp(location, it, "load_varargs"); + printUnaryOp(exec, location, it, "load_varargs"); break; } case op_tear_off_activation: { int r0 = (++it)->u.operand; - printf("[%4d] tear_off_activation\t %s\n", location, registerName(r0).c_str()); + printf("[%4d] tear_off_activation\t %s\n", location, registerName(exec, r0).c_str()); break; } case op_tear_off_arguments: { @@ -985,7 +1006,7 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_ret: { int r0 = (++it)->u.operand; - printf("[%4d] ret\t\t %s\n", location, registerName(r0).c_str()); + printf("[%4d] ret\t\t %s\n", location, registerName(exec, r0).c_str()); break; } case op_construct: { @@ -995,44 +1016,49 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int registerOffset = (++it)->u.operand; int proto = (++it)->u.operand; int thisRegister = (++it)->u.operand; - printf("[%4d] construct\t %s, %s, %d, %d, %s, %s\n", location, registerName(dst).c_str(), registerName(func).c_str(), argCount, registerOffset, registerName(proto).c_str(), registerName(thisRegister).c_str()); + printf("[%4d] construct\t %s, %s, %d, %d, %s, %s\n", location, registerName(exec, dst).c_str(), registerName(exec, func).c_str(), argCount, registerOffset, registerName(exec, proto).c_str(), registerName(exec, thisRegister).c_str()); break; } case op_construct_verify: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] construct_verify\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str()); + printf("[%4d] construct_verify\t %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str()); break; } case op_strcat: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; int count = (++it)->u.operand; - printf("[%4d] op_strcat\t %s, %s, %d\n", location, registerName(r0).c_str(), registerName(r1).c_str(), count); + printf("[%4d] strcat\t\t %s, %s, %d\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), count); break; } case op_to_primitive: { int r0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] op_to_primitive\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str()); + printf("[%4d] to_primitive\t %s, %s\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str()); break; } case op_get_pnames: { - int r0 = (++it)->u.operand; - int r1 = (++it)->u.operand; - printf("[%4d] get_pnames\t %s, %s\n", location, registerName(r0).c_str(), registerName(r1).c_str()); + int r0 = it[1].u.operand; + int r1 = it[2].u.operand; + int r2 = it[3].u.operand; + int r3 = it[4].u.operand; + int offset = it[5].u.operand; + printf("[%4d] get_pnames\t %s, %s, %s, %s, %d(->%d)\n", location, registerName(exec, r0).c_str(), registerName(exec, r1).c_str(), registerName(exec, r2).c_str(), registerName(exec, r3).c_str(), offset, location + offset); + it += OPCODE_LENGTH(op_get_pnames) - 1; break; } case op_next_pname: { - int dest = (++it)->u.operand; - int iter = (++it)->u.operand; - int offset = (++it)->u.operand; - printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(dest).c_str(), registerName(iter).c_str(), offset, locationForOffset(begin, it, offset)); + int dest = it[1].u.operand; + int iter = it[4].u.operand; + int offset = it[5].u.operand; + printf("[%4d] next_pname\t %s, %s, %d(->%d)\n", location, registerName(exec, dest).c_str(), registerName(exec, iter).c_str(), offset, location + offset); + it += OPCODE_LENGTH(op_next_pname) - 1; break; } case op_push_scope: { int r0 = (++it)->u.operand; - printf("[%4d] push_scope\t %s\n", location, registerName(r0).c_str()); + printf("[%4d] push_scope\t %s\n", location, registerName(exec, r0).c_str()); break; } case op_pop_scope: { @@ -1043,41 +1069,41 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& int r0 = (++it)->u.operand; int id0 = (++it)->u.operand; int r1 = (++it)->u.operand; - printf("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(r1).c_str()); + printf("[%4d] push_new_scope \t%s, %s, %s\n", location, registerName(exec, r0).c_str(), idName(id0, m_identifiers[id0]).c_str(), registerName(exec, r1).c_str()); break; } case op_jmp_scopes: { int scopeDelta = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, locationForOffset(begin, it, offset)); + printf("[%4d] jmp_scopes\t^%d, %d(->%d)\n", location, scopeDelta, offset, location + offset); break; } case op_catch: { int r0 = (++it)->u.operand; - printf("[%4d] catch\t\t %s\n", location, registerName(r0).c_str()); + printf("[%4d] catch\t\t %s\n", location, registerName(exec, r0).c_str()); break; } case op_throw: { int r0 = (++it)->u.operand; - printf("[%4d] throw\t\t %s\n", location, registerName(r0).c_str()); + printf("[%4d] throw\t\t %s\n", location, registerName(exec, r0).c_str()); break; } case op_new_error: { int r0 = (++it)->u.operand; int errorType = (++it)->u.operand; int k0 = (++it)->u.operand; - printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(r0).c_str(), errorType, constantName(exec, k0, getConstant(k0)).c_str()); + printf("[%4d] new_error\t %s, %d, %s\n", location, registerName(exec, r0).c_str(), errorType, constantName(exec, k0, getConstant(k0)).c_str()); break; } case op_jsr: { int retAddrDst = (++it)->u.operand; int offset = (++it)->u.operand; - printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(retAddrDst).c_str(), offset, locationForOffset(begin, it, offset)); + printf("[%4d] jsr\t\t %s, %d(->%d)\n", location, registerName(exec, retAddrDst).c_str(), offset, location + offset); break; } case op_sret: { int retAddrSrc = (++it)->u.operand; - printf("[%4d] sret\t\t %s\n", location, registerName(retAddrSrc).c_str()); + printf("[%4d] sret\t\t %s\n", location, registerName(exec, retAddrSrc).c_str()); break; } case op_debug: { @@ -1089,17 +1115,17 @@ void CodeBlock::dump(ExecState* exec, const Vector<Instruction>::const_iterator& } case op_profile_will_call: { int function = (++it)->u.operand; - printf("[%4d] profile_will_call %s\n", location, registerName(function).c_str()); + printf("[%4d] profile_will_call %s\n", location, registerName(exec, function).c_str()); break; } case op_profile_did_call: { int function = (++it)->u.operand; - printf("[%4d] profile_did_call\t %s\n", location, registerName(function).c_str()); + printf("[%4d] profile_did_call\t %s\n", location, registerName(exec, function).c_str()); break; } case op_end: { int r0 = (++it)->u.operand; - printf("[%4d] end\t\t %s\n", location, registerName(r0).c_str()); + printf("[%4d] end\t\t %s\n", location, registerName(exec, r0).c_str()); break; } } @@ -1246,43 +1272,22 @@ void CodeBlock::dumpStatistics() #endif } -CodeBlock::CodeBlock(ScopeNode* ownerNode) - : m_numCalleeRegisters(0) - , m_numVars(0) - , m_numParameters(0) - , m_ownerNode(ownerNode) - , m_globalData(0) -#ifndef NDEBUG - , m_instructionCount(0) -#endif - , m_needsFullScopeChain(false) - , m_usesEval(false) - , m_isNumericCompareFunction(false) - , m_codeType(NativeCode) - , m_source(0) - , m_sourceOffset(0) - , m_exceptionInfo(0) -{ -#if DUMP_CODE_BLOCK_STATISTICS - liveCodeBlockSet.add(this); -#endif -} - -CodeBlock::CodeBlock(ScopeNode* ownerNode, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset) +CodeBlock::CodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, SymbolTable* symTab) : m_numCalleeRegisters(0) , m_numVars(0) , m_numParameters(0) - , m_ownerNode(ownerNode) + , m_ownerExecutable(ownerExecutable) , m_globalData(0) #ifndef NDEBUG , m_instructionCount(0) #endif - , m_needsFullScopeChain(ownerNode->needsActivation()) - , m_usesEval(ownerNode->usesEval()) + , m_needsFullScopeChain(ownerExecutable->needsActivation()) + , m_usesEval(ownerExecutable->usesEval()) , m_isNumericCompareFunction(false) , m_codeType(codeType) , m_source(sourceProvider) , m_sourceOffset(sourceOffset) + , m_symbolTable(symTab) , m_exceptionInfo(new ExceptionInfo) { ASSERT(m_source); @@ -1350,7 +1355,6 @@ void CodeBlock::unlinkCallers() void CodeBlock::derefStructures(Instruction* vPC) const { - ASSERT(m_codeType != NativeCode); Interpreter* interpreter = m_globalData->interpreter; if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) { @@ -1396,7 +1400,6 @@ void CodeBlock::derefStructures(Instruction* vPC) const void CodeBlock::refStructures(Instruction* vPC) const { - ASSERT(m_codeType != NativeCode); Interpreter* interpreter = m_globalData->interpreter; if (vPC[0].u.opcode == interpreter->getOpcode(op_get_by_id_self)) { @@ -1430,25 +1433,16 @@ void CodeBlock::refStructures(Instruction* vPC) const void CodeBlock::markAggregate(MarkStack& markStack) { - for (size_t i = 0; i < m_constantRegisters.size(); ++i) { - if (!m_constantRegisters[i].marked()) - markStack.append(m_constantRegisters[i].jsValue()); - } - - for (size_t i = 0; i < m_functionExpressions.size(); ++i) - m_functionExpressions[i]->body()->markAggregate(markStack); - - if (m_rareData) { - for (size_t i = 0; i < m_rareData->m_functions.size(); ++i) - m_rareData->m_functions[i]->body()->markAggregate(markStack); - - m_rareData->m_evalCodeCache.markAggregate(markStack); - } + for (size_t i = 0; i < m_constantRegisters.size(); ++i) + markStack.append(m_constantRegisters[i].jsValue()); + for (size_t i = 0; i < m_functionExprs.size(); ++i) + m_functionExprs[i]->markAggregate(markStack); + for (size_t i = 0; i < m_functionDecls.size(); ++i) + m_functionDecls[i]->markAggregate(markStack); } void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame) { - ASSERT(m_codeType != NativeCode); if (m_exceptionInfo) return; @@ -1465,61 +1459,11 @@ void CodeBlock::reparseForExceptionInfoIfNecessary(CallFrame* callFrame) scopeChain = scopeChain->next; } - switch (m_codeType) { - case FunctionCode: { - FunctionBodyNode* ownerFunctionBodyNode = static_cast<FunctionBodyNode*>(m_ownerNode); - RefPtr<FunctionBodyNode> newFunctionBody = m_globalData->parser->reparse<FunctionBodyNode>(m_globalData, ownerFunctionBodyNode); - ASSERT(newFunctionBody); - newFunctionBody->finishParsing(ownerFunctionBodyNode->copyParameters(), ownerFunctionBodyNode->parameterCount()); - - m_globalData->scopeNodeBeingReparsed = newFunctionBody.get(); - - CodeBlock& newCodeBlock = newFunctionBody->bytecodeForExceptionInfoReparse(scopeChain, this); - ASSERT(newCodeBlock.m_exceptionInfo); - ASSERT(newCodeBlock.m_instructionCount == m_instructionCount); - -#if ENABLE(JIT) - JIT::compile(m_globalData, &newCodeBlock); - ASSERT(newFunctionBody->generatedJITCode().size() == ownerNode()->generatedJITCode().size()); -#endif - - m_exceptionInfo.set(newCodeBlock.m_exceptionInfo.release()); - - m_globalData->scopeNodeBeingReparsed = 0; - - break; - } - case EvalCode: { - EvalNode* ownerEvalNode = static_cast<EvalNode*>(m_ownerNode); - RefPtr<EvalNode> newEvalBody = m_globalData->parser->reparse<EvalNode>(m_globalData, ownerEvalNode); - - m_globalData->scopeNodeBeingReparsed = newEvalBody.get(); - - EvalCodeBlock& newCodeBlock = newEvalBody->bytecodeForExceptionInfoReparse(scopeChain, this); - ASSERT(newCodeBlock.m_exceptionInfo); - ASSERT(newCodeBlock.m_instructionCount == m_instructionCount); - -#if ENABLE(JIT) - JIT::compile(m_globalData, &newCodeBlock); - ASSERT(newEvalBody->generatedJITCode().size() == ownerNode()->generatedJITCode().size()); -#endif - - m_exceptionInfo.set(newCodeBlock.m_exceptionInfo.release()); - - m_globalData->scopeNodeBeingReparsed = 0; - - break; - } - default: - // CodeBlocks for Global code blocks are transient and therefore to not gain from - // from throwing out there exception information. - ASSERT_NOT_REACHED(); - } + m_exceptionInfo.set(m_ownerExecutable->reparseExceptionInfo(m_globalData, scopeChain, this)); } HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset) { - ASSERT(m_codeType != NativeCode); ASSERT(bytecodeOffset < m_instructionCount); if (!m_rareData) @@ -1538,14 +1482,13 @@ HandlerInfo* CodeBlock::handlerForBytecodeOffset(unsigned bytecodeOffset) int CodeBlock::lineNumberForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset) { - ASSERT(m_codeType != NativeCode); ASSERT(bytecodeOffset < m_instructionCount); reparseForExceptionInfoIfNecessary(callFrame); ASSERT(m_exceptionInfo); if (!m_exceptionInfo->m_lineInfo.size()) - return m_ownerNode->source().firstLine(); // Empty function + return m_ownerExecutable->source().firstLine(); // Empty function int low = 0; int high = m_exceptionInfo->m_lineInfo.size(); @@ -1558,13 +1501,12 @@ int CodeBlock::lineNumberForBytecodeOffset(CallFrame* callFrame, unsigned byteco } if (!low) - return m_ownerNode->source().firstLine(); + return m_ownerExecutable->source().firstLine(); return m_exceptionInfo->m_lineInfo[low - 1].lineNumber; } int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, int& divot, int& startOffset, int& endOffset) { - ASSERT(m_codeType != NativeCode); ASSERT(bytecodeOffset < m_instructionCount); reparseForExceptionInfoIfNecessary(callFrame); @@ -1604,7 +1546,6 @@ int CodeBlock::expressionRangeForBytecodeOffset(CallFrame* callFrame, unsigned b bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame* callFrame, unsigned bytecodeOffset, OpcodeID& opcodeID) { - ASSERT(m_codeType != NativeCode); ASSERT(bytecodeOffset < m_instructionCount); reparseForExceptionInfoIfNecessary(callFrame); @@ -1633,7 +1574,6 @@ bool CodeBlock::getByIdExceptionInfoForBytecodeOffset(CallFrame* callFrame, unsi #if ENABLE(JIT) bool CodeBlock::functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex) { - ASSERT(m_codeType != NativeCode); ASSERT(bytecodeOffset < m_instructionCount); if (!m_rareData || !m_rareData->m_functionRegisterInfos.size()) @@ -1660,7 +1600,6 @@ bool CodeBlock::functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& #if !ENABLE(JIT) bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOffset) { - ASSERT(m_codeType != NativeCode); if (m_globalResolveInstructions.isEmpty()) return false; @@ -1681,7 +1620,6 @@ bool CodeBlock::hasGlobalResolveInstructionAtBytecodeOffset(unsigned bytecodeOff #else bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset) { - ASSERT(m_codeType != NativeCode); if (m_globalResolveInfos.isEmpty()) return false; @@ -1701,18 +1639,6 @@ bool CodeBlock::hasGlobalResolveInfoAtBytecodeOffset(unsigned bytecodeOffset) } #endif -#if ENABLE(JIT) -void CodeBlock::setJITCode(JITCode jitCode) -{ - ASSERT(m_codeType != NativeCode); - ownerNode()->setJITCode(jitCode); -#if !ENABLE(OPCODE_SAMPLING) - if (!BytecodeGenerator::dumpsGeneratedCode()) - m_instructions.clear(); -#endif -} -#endif - void CodeBlock::shrinkToFit() { m_instructions.shrinkToFit(); @@ -1728,7 +1654,8 @@ void CodeBlock::shrinkToFit() #endif m_identifiers.shrinkToFit(); - m_functionExpressions.shrinkToFit(); + m_functionDecls.shrinkToFit(); + m_functionExprs.shrinkToFit(); m_constantRegisters.shrinkToFit(); if (m_exceptionInfo) { @@ -1739,7 +1666,6 @@ void CodeBlock::shrinkToFit() if (m_rareData) { m_rareData->m_exceptionHandlers.shrinkToFit(); - m_rareData->m_functions.shrinkToFit(); m_rareData->m_regexps.shrinkToFit(); m_rareData->m_immediateSwitchJumpTables.shrinkToFit(); m_rareData->m_characterSwitchJumpTables.shrinkToFit(); diff --git a/JavaScriptCore/bytecode/CodeBlock.h b/JavaScriptCore/bytecode/CodeBlock.h index 39b1db3..eb874cc 100644 --- a/JavaScriptCore/bytecode/CodeBlock.h +++ b/JavaScriptCore/bytecode/CodeBlock.h @@ -61,7 +61,7 @@ namespace JSC { class ExecState; - enum CodeType { GlobalCode, EvalCode, FunctionCode, NativeCode }; + enum CodeType { GlobalCode, EvalCode, FunctionCode }; static ALWAYS_INLINE int missingThisObjectMarker() { return std::numeric_limits<int>::max(); } @@ -248,12 +248,22 @@ namespace JSC { } #endif + struct ExceptionInfo : FastAllocBase { + Vector<ExpressionRangeInfo> m_expressionInfo; + Vector<LineInfo> m_lineInfo; + Vector<GetByIdExceptionInfo> m_getByIdExceptionInfo; + +#if ENABLE(JIT) + Vector<CallReturnOffsetToBytecodeIndex> m_callReturnIndexVector; +#endif + }; + class CodeBlock : public FastAllocBase { friend class JIT; + protected: + CodeBlock(ScriptExecutable* ownerExecutable, CodeType, PassRefPtr<SourceProvider>, unsigned sourceOffset, SymbolTable* symbolTable); public: - CodeBlock(ScopeNode* ownerNode); - CodeBlock(ScopeNode* ownerNode, CodeType, PassRefPtr<SourceProvider>, unsigned sourceOffset); - ~CodeBlock(); + virtual ~CodeBlock(); void markAggregate(MarkStack&); void refStructures(Instruction* vPC) const; @@ -329,7 +339,7 @@ namespace JSC { unsigned getBytecodeIndex(CallFrame* callFrame, ReturnAddressPtr returnAddress) { reparseForExceptionInfoIfNecessary(callFrame); - return binaryChop<CallReturnOffsetToBytecodeIndex, unsigned, getCallReturnOffset>(callReturnIndexVector().begin(), callReturnIndexVector().size(), ownerNode()->generatedJITCode().offsetOf(returnAddress.value()))->bytecodeIndex; + return binaryChop<CallReturnOffsetToBytecodeIndex, unsigned, getCallReturnOffset>(callReturnIndexVector().begin(), callReturnIndexVector().size(), ownerExecutable()->generatedJITCode().offsetOf(returnAddress.value()))->bytecodeIndex; } bool functionRegisterForBytecodeOffset(unsigned bytecodeOffset, int& functionRegisterIndex); @@ -339,17 +349,19 @@ namespace JSC { bool isNumericCompareFunction() { return m_isNumericCompareFunction; } Vector<Instruction>& instructions() { return m_instructions; } + void discardBytecode() { m_instructions.clear(); } + #ifndef NDEBUG + unsigned instructionCount() { return m_instructionCount; } void setInstructionCount(unsigned instructionCount) { m_instructionCount = instructionCount; } #endif #if ENABLE(JIT) - JITCode& getJITCode() { return ownerNode()->generatedJITCode(); } - void setJITCode(JITCode); - ExecutablePool* executablePool() { return ownerNode()->getExecutablePool(); } + JITCode& getJITCode() { return ownerExecutable()->generatedJITCode(); } + ExecutablePool* executablePool() { return ownerExecutable()->getExecutablePool(); } #endif - ScopeNode* ownerNode() const { return m_ownerNode; } + ScriptExecutable* ownerExecutable() const { return m_ownerExecutable; } void setGlobalData(JSGlobalData* globalData) { m_globalData = globalData; } @@ -365,8 +377,8 @@ namespace JSC { CodeType codeType() const { return m_codeType; } - SourceProvider* source() const { ASSERT(m_codeType != NativeCode); return m_source.get(); } - unsigned sourceOffset() const { ASSERT(m_codeType != NativeCode); return m_sourceOffset; } + SourceProvider* source() const { return m_source.get(); } + unsigned sourceOffset() const { return m_sourceOffset; } size_t numberOfJumpTargets() const { return m_jumpTargets.size(); } void addJumpTarget(unsigned jumpTarget) { m_jumpTargets.append(jumpTarget); } @@ -404,6 +416,7 @@ namespace JSC { bool hasExceptionInfo() const { return m_exceptionInfo; } void clearExceptionInfo() { m_exceptionInfo.clear(); } + ExceptionInfo* extractExceptionInfo() { ASSERT(m_exceptionInfo); return m_exceptionInfo.release(); } void addExpressionInfo(const ExpressionRangeInfo& expressionInfo) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_expressionInfo.append(expressionInfo); } void addGetByIdExceptionInfo(const GetByIdExceptionInfo& info) { ASSERT(m_exceptionInfo); m_exceptionInfo->m_getByIdExceptionInfo.append(info); } @@ -425,16 +438,14 @@ namespace JSC { size_t numberOfConstantRegisters() const { return m_constantRegisters.size(); } void addConstantRegister(const Register& r) { return m_constantRegisters.append(r); } Register& constantRegister(int index) { return m_constantRegisters[index - FirstConstantRegisterIndex]; } - ALWAYS_INLINE bool isConstantRegisterIndex(int index) { return index >= FirstConstantRegisterIndex; } + ALWAYS_INLINE bool isConstantRegisterIndex(int index) const { return index >= FirstConstantRegisterIndex; } ALWAYS_INLINE JSValue getConstant(int index) const { return m_constantRegisters[index - FirstConstantRegisterIndex].jsValue(); } - unsigned addFunctionExpression(FuncExprNode* n) { unsigned size = m_functionExpressions.size(); m_functionExpressions.append(n); return size; } - FuncExprNode* functionExpression(int index) const { return m_functionExpressions[index].get(); } - - unsigned addFunction(FuncDeclNode* n) { createRareDataIfNecessary(); unsigned size = m_rareData->m_functions.size(); m_rareData->m_functions.append(n); return size; } - FuncDeclNode* function(int index) const { ASSERT(m_rareData); return m_rareData->m_functions[index].get(); } - - bool hasFunctions() const { return m_functionExpressions.size() || (m_rareData && m_rareData->m_functions.size()); } + unsigned addFunctionDecl(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionDecls.size(); m_functionDecls.append(n); return size; } + FunctionExecutable* functionDecl(int index) { return m_functionDecls[index].get(); } + int numberOfFunctionDecls() { return m_functionDecls.size(); } + unsigned addFunctionExpr(NonNullPassRefPtr<FunctionExecutable> n) { unsigned size = m_functionExprs.size(); m_functionExprs.append(n); return size; } + FunctionExecutable* functionExpr(int index) { return m_functionExprs[index].get(); } unsigned addRegExp(RegExp* r) { createRareDataIfNecessary(); unsigned size = m_rareData->m_regexps.size(); m_rareData->m_regexps.append(r); return size; } RegExp* regexp(int index) const { ASSERT(m_rareData); return m_rareData->m_regexps[index].get(); } @@ -455,9 +466,10 @@ namespace JSC { StringJumpTable& stringSwitchJumpTable(int tableIndex) { ASSERT(m_rareData); return m_rareData->m_stringSwitchJumpTables[tableIndex]; } - SymbolTable& symbolTable() { return m_symbolTable; } + SymbolTable* symbolTable() { return m_symbolTable; } + SharedSymbolTable* sharedSymbolTable() { ASSERT(m_codeType == FunctionCode); return static_cast<SharedSymbolTable*>(m_symbolTable); } - EvalCodeCache& evalCodeCache() { ASSERT(m_codeType != NativeCode); createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; } + EvalCodeCache& evalCodeCache() { createRareDataIfNecessary(); return m_rareData->m_evalCodeCache; } void shrinkToFit(); @@ -470,18 +482,24 @@ namespace JSC { private: #if !defined(NDEBUG) || ENABLE(OPCODE_SAMPLING) void dump(ExecState*, const Vector<Instruction>::const_iterator& begin, Vector<Instruction>::const_iterator&) const; + + CString registerName(ExecState*, int r) const; + void printUnaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; + void printBinaryOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; + void printConditionalJump(ExecState*, const Vector<Instruction>::const_iterator&, Vector<Instruction>::const_iterator&, int location, const char* op) const; + void printGetByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; + void printPutByIdOp(ExecState*, int location, Vector<Instruction>::const_iterator&, const char* op) const; #endif void reparseForExceptionInfoIfNecessary(CallFrame*); void createRareDataIfNecessary() { - ASSERT(m_codeType != NativeCode); if (!m_rareData) m_rareData.set(new RareData); } - ScopeNode* m_ownerNode; + ScriptExecutable* m_ownerExecutable; JSGlobalData* m_globalData; Vector<Instruction> m_instructions; @@ -517,26 +535,17 @@ namespace JSC { // Constant Pool Vector<Identifier> m_identifiers; Vector<Register> m_constantRegisters; - Vector<RefPtr<FuncExprNode> > m_functionExpressions; + Vector<RefPtr<FunctionExecutable> > m_functionDecls; + Vector<RefPtr<FunctionExecutable> > m_functionExprs; - SymbolTable m_symbolTable; + SymbolTable* m_symbolTable; - struct ExceptionInfo : FastAllocBase { - Vector<ExpressionRangeInfo> m_expressionInfo; - Vector<LineInfo> m_lineInfo; - Vector<GetByIdExceptionInfo> m_getByIdExceptionInfo; - -#if ENABLE(JIT) - Vector<CallReturnOffsetToBytecodeIndex> m_callReturnIndexVector; -#endif - }; OwnPtr<ExceptionInfo> m_exceptionInfo; struct RareData : FastAllocBase { Vector<HandlerInfo> m_exceptionHandlers; // Rare Constants - Vector<RefPtr<FuncDeclNode> > m_functions; Vector<RefPtr<RegExp> > m_regexps; // Jump Tables @@ -556,16 +565,16 @@ namespace JSC { // Program code is not marked by any function, so we make the global object // responsible for marking it. - class ProgramCodeBlock : public CodeBlock { + class GlobalCodeBlock : public CodeBlock { public: - ProgramCodeBlock(ScopeNode* ownerNode, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider) - : CodeBlock(ownerNode, codeType, sourceProvider, 0) + GlobalCodeBlock(ScriptExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset, JSGlobalObject* globalObject) + : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, &m_unsharedSymbolTable) , m_globalObject(globalObject) { m_globalObject->codeBlocks().add(this); } - ~ProgramCodeBlock() + ~GlobalCodeBlock() { if (m_globalObject) m_globalObject->codeBlocks().remove(this); @@ -575,20 +584,54 @@ namespace JSC { private: JSGlobalObject* m_globalObject; // For program and eval nodes, the global object that marks the constant pool. + SymbolTable m_unsharedSymbolTable; + }; + + class ProgramCodeBlock : public GlobalCodeBlock { + public: + ProgramCodeBlock(ProgramExecutable* ownerExecutable, CodeType codeType, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider) + : GlobalCodeBlock(ownerExecutable, codeType, sourceProvider, 0, globalObject) + { + } }; - class EvalCodeBlock : public ProgramCodeBlock { + class EvalCodeBlock : public GlobalCodeBlock { public: - EvalCodeBlock(ScopeNode* ownerNode, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth) - : ProgramCodeBlock(ownerNode, EvalCode, globalObject, sourceProvider) + EvalCodeBlock(EvalExecutable* ownerExecutable, JSGlobalObject* globalObject, PassRefPtr<SourceProvider> sourceProvider, int baseScopeDepth) + : GlobalCodeBlock(ownerExecutable, EvalCode, sourceProvider, 0, globalObject) , m_baseScopeDepth(baseScopeDepth) { } int baseScopeDepth() const { return m_baseScopeDepth; } + const Identifier& variable(unsigned index) { return m_variables[index]; } + unsigned numVariables() { return m_variables.size(); } + void adoptVariables(Vector<Identifier>& variables) + { + ASSERT(m_variables.isEmpty()); + m_variables.swap(variables); + } + private: int m_baseScopeDepth; + Vector<Identifier> m_variables; + }; + + class FunctionCodeBlock : public CodeBlock { + public: + // Rather than using the usual RefCounted::create idiom for SharedSymbolTable we just use new + // as we need to initialise the CodeBlock before we could initialise any RefPtr to hold the shared + // symbol table, so we just pass as a raw pointer with a ref count of 1. We then manually deref + // in the destructor. + FunctionCodeBlock(FunctionExecutable* ownerExecutable, CodeType codeType, PassRefPtr<SourceProvider> sourceProvider, unsigned sourceOffset) + : CodeBlock(ownerExecutable, codeType, sourceProvider, sourceOffset, new SharedSymbolTable) + { + } + ~FunctionCodeBlock() + { + sharedSymbolTable()->deref(); + } }; inline Register& ExecState::r(int index) diff --git a/JavaScriptCore/bytecode/EvalCodeCache.h b/JavaScriptCore/bytecode/EvalCodeCache.h index 986525c..05834fc 100644 --- a/JavaScriptCore/bytecode/EvalCodeCache.h +++ b/JavaScriptCore/bytecode/EvalCodeCache.h @@ -29,6 +29,7 @@ #ifndef EvalCodeCache_h #define EvalCodeCache_h +#include "Executable.h" #include "JSGlobalObject.h" #include "Nodes.h" #include "Parser.h" @@ -41,44 +42,33 @@ namespace JSC { class EvalCodeCache { public: - PassRefPtr<EvalNode> get(ExecState* exec, const UString& evalSource, ScopeChainNode* scopeChain, JSValue& exceptionValue) + PassRefPtr<EvalExecutable> get(ExecState* exec, const UString& evalSource, ScopeChainNode* scopeChain, JSValue& exceptionValue) { - RefPtr<EvalNode> evalNode; + RefPtr<EvalExecutable> evalExecutable; if (evalSource.size() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject()) - evalNode = m_cacheMap.get(evalSource.rep()); + evalExecutable = m_cacheMap.get(evalSource.rep()); - if (!evalNode) { - int errorLine; - UString errorMessage; - - SourceCode source = makeSource(evalSource); - evalNode = exec->globalData().parser->parse<EvalNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errorLine, &errorMessage); - if (evalNode) { - if (evalSource.size() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && m_cacheMap.size() < maxCacheEntries) - m_cacheMap.set(evalSource.rep(), evalNode); - } else { - exceptionValue = Error::create(exec, SyntaxError, errorMessage, errorLine, source.provider()->asID(), 0); + if (!evalExecutable) { + evalExecutable = EvalExecutable::create(exec, makeSource(evalSource)); + exceptionValue = evalExecutable->compile(exec, scopeChain); + if (exceptionValue) return 0; - } + + if (evalSource.size() < maxCacheableSourceLength && (*scopeChain->begin())->isVariableObject() && m_cacheMap.size() < maxCacheEntries) + m_cacheMap.set(evalSource.rep(), evalExecutable); } - return evalNode.release(); + return evalExecutable.release(); } bool isEmpty() const { return m_cacheMap.isEmpty(); } - void markAggregate(MarkStack& markStack) - { - EvalCacheMap::iterator end = m_cacheMap.end(); - for (EvalCacheMap::iterator ptr = m_cacheMap.begin(); ptr != end; ++ptr) - ptr->second->markAggregate(markStack); - } private: static const int maxCacheableSourceLength = 256; static const int maxCacheEntries = 64; - typedef HashMap<RefPtr<UString::Rep>, RefPtr<EvalNode> > EvalCacheMap; + typedef HashMap<RefPtr<UString::Rep>, RefPtr<EvalExecutable> > EvalCacheMap; EvalCacheMap m_cacheMap; }; diff --git a/JavaScriptCore/bytecode/Opcode.h b/JavaScriptCore/bytecode/Opcode.h index c9196ce..e88f051 100644 --- a/JavaScriptCore/bytecode/Opcode.h +++ b/JavaScriptCore/bytecode/Opcode.h @@ -113,6 +113,7 @@ namespace JSC { macro(op_put_by_id_generic, 8) \ macro(op_del_by_id, 4) \ macro(op_get_by_val, 4) \ + macro(op_get_by_pname, 7) \ macro(op_put_by_val, 4) \ macro(op_del_by_val, 4) \ macro(op_put_by_index, 4) \ @@ -127,9 +128,11 @@ namespace JSC { macro(op_jneq_ptr, 4) \ macro(op_jnless, 4) \ macro(op_jnlesseq, 4) \ + macro(op_jless, 4) \ macro(op_jmp_scopes, 3) \ macro(op_loop, 2) \ macro(op_loop_if_true, 3) \ + macro(op_loop_if_false, 3) \ macro(op_loop_if_less, 4) \ macro(op_loop_if_lesseq, 4) \ macro(op_switch_imm, 4) \ @@ -152,8 +155,8 @@ namespace JSC { macro(op_strcat, 4) \ macro(op_to_primitive, 3) \ \ - macro(op_get_pnames, 3) \ - macro(op_next_pname, 4) \ + macro(op_get_pnames, 6) \ + macro(op_next_pname, 7) \ \ macro(op_push_scope, 2) \ macro(op_pop_scope, 1) \ diff --git a/JavaScriptCore/bytecode/SamplingTool.cpp b/JavaScriptCore/bytecode/SamplingTool.cpp index 8651723..865c919 100644 --- a/JavaScriptCore/bytecode/SamplingTool.cpp +++ b/JavaScriptCore/bytecode/SamplingTool.cpp @@ -157,7 +157,7 @@ void SamplingThread::stop() } -void ScopeSampleRecord::sample(CodeBlock* codeBlock, Instruction* vPC) +void ScriptSampleRecord::sample(CodeBlock* codeBlock, Instruction* vPC) { if (!m_samples) { m_size = codeBlock->instructions().size(); @@ -196,8 +196,8 @@ void SamplingTool::doRun() #if ENABLE(CODEBLOCK_SAMPLING) if (CodeBlock* codeBlock = sample.codeBlock()) { - MutexLocker locker(m_scopeSampleMapMutex); - ScopeSampleRecord* record = m_scopeSampleMap->get(codeBlock->ownerNode()); + MutexLocker locker(m_scriptSampleMapMutex); + ScriptSampleRecord* record = m_scopeSampleMap->get(codeBlock->ownerExecutable()); ASSERT(record); record->sample(codeBlock, sample.vPC()); } @@ -209,13 +209,13 @@ void SamplingTool::sample() s_samplingTool->doRun(); } -void SamplingTool::notifyOfScope(ScopeNode* scope) +void SamplingTool::notifyOfScope(ScriptExecutable* script) { #if ENABLE(CODEBLOCK_SAMPLING) - MutexLocker locker(m_scopeSampleMapMutex); - m_scopeSampleMap->set(scope, new ScopeSampleRecord(scope)); + MutexLocker locker(m_scriptSampleMapMutex); + m_scopeSampleMap->set(script, new ScriptSampleRecord(script)); #else - UNUSED_PARAM(scope); + UNUSED_PARAM(script); #endif } @@ -254,10 +254,10 @@ static int compareLineCountInfoSampling(const void* left, const void* right) return (leftLineCount->line > rightLineCount->line) ? 1 : (leftLineCount->line < rightLineCount->line) ? -1 : 0; } -static int compareScopeSampleRecords(const void* left, const void* right) +static int compareScriptSampleRecords(const void* left, const void* right) { - const ScopeSampleRecord* const leftValue = *static_cast<const ScopeSampleRecord* const *>(left); - const ScopeSampleRecord* const rightValue = *static_cast<const ScopeSampleRecord* const *>(right); + const ScriptSampleRecord* const leftValue = *static_cast<const ScriptSampleRecord* const *>(left); + const ScriptSampleRecord* const rightValue = *static_cast<const ScriptSampleRecord* const *>(right); return (leftValue->m_sampleCount < rightValue->m_sampleCount) ? 1 : (leftValue->m_sampleCount > rightValue->m_sampleCount) ? -1 : 0; } @@ -318,26 +318,26 @@ void SamplingTool::dump(ExecState* exec) // (3) Build and sort 'codeBlockSamples' array. int scopeCount = m_scopeSampleMap->size(); - Vector<ScopeSampleRecord*> codeBlockSamples(scopeCount); - ScopeSampleRecordMap::iterator iter = m_scopeSampleMap->begin(); + Vector<ScriptSampleRecord*> codeBlockSamples(scopeCount); + ScriptSampleRecordMap::iterator iter = m_scopeSampleMap->begin(); for (int i = 0; i < scopeCount; ++i, ++iter) codeBlockSamples[i] = iter->second; - qsort(codeBlockSamples.begin(), scopeCount, sizeof(ScopeSampleRecord*), compareScopeSampleRecords); + qsort(codeBlockSamples.begin(), scopeCount, sizeof(ScriptSampleRecord*), compareScriptSampleRecords); // (4) Print data from 'codeBlockSamples' array. printf("\nCodeBlock samples\n\n"); for (int i = 0; i < scopeCount; ++i) { - ScopeSampleRecord* record = codeBlockSamples[i]; + ScriptSampleRecord* record = codeBlockSamples[i]; CodeBlock* codeBlock = record->m_codeBlock; double blockPercent = (record->m_sampleCount * 100.0) / m_sampleCount; if (blockPercent >= 1) { //Instruction* code = codeBlock->instructions().begin(); - printf("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_scope->sourceURL().UTF8String().c_str(), codeBlock->lineNumberForBytecodeOffset(exec, 0), record->m_sampleCount, m_sampleCount, blockPercent); + printf("#%d: %s:%d: %d / %lld (%.3f%%)\n", i + 1, record->m_executable->sourceURL().UTF8String().c_str(), codeBlock->lineNumberForBytecodeOffset(exec, 0), record->m_sampleCount, m_sampleCount, blockPercent); if (i < 10) { HashMap<unsigned,unsigned> lineCounts; codeBlock->dump(exec); diff --git a/JavaScriptCore/bytecode/SamplingTool.h b/JavaScriptCore/bytecode/SamplingTool.h index 1a3f7cf..8e3ed9e 100644 --- a/JavaScriptCore/bytecode/SamplingTool.h +++ b/JavaScriptCore/bytecode/SamplingTool.h @@ -38,6 +38,8 @@ namespace JSC { + class ScriptExecutable; + class SamplingFlags { friend class JIT; public: @@ -92,9 +94,9 @@ namespace JSC { class ScopeNode; struct Instruction; - struct ScopeSampleRecord { - ScopeSampleRecord(ScopeNode* scope) - : m_scope(scope) + struct ScriptSampleRecord { + ScriptSampleRecord(ScriptExecutable* executable) + : m_executable(executable) , m_codeBlock(0) , m_sampleCount(0) , m_opcodeSampleCount(0) @@ -103,7 +105,7 @@ namespace JSC { { } - ~ScopeSampleRecord() + ~ScriptSampleRecord() { if (m_samples) free(m_samples); @@ -111,7 +113,7 @@ namespace JSC { void sample(CodeBlock*, Instruction*); - RefPtr<ScopeNode> m_scope; + RefPtr<ScriptExecutable> m_executable; CodeBlock* m_codeBlock; int m_sampleCount; int m_opcodeSampleCount; @@ -119,7 +121,7 @@ namespace JSC { unsigned m_size; }; - typedef WTF::HashMap<ScopeNode*, ScopeSampleRecord*> ScopeSampleRecordMap; + typedef WTF::HashMap<ScriptExecutable*, ScriptSampleRecord*> ScriptSampleRecordMap; class SamplingThread { public: @@ -193,7 +195,7 @@ namespace JSC { , m_sampleCount(0) , m_opcodeSampleCount(0) #if ENABLE(CODEBLOCK_SAMPLING) - , m_scopeSampleMap(new ScopeSampleRecordMap()) + , m_scopeSampleMap(new ScriptSampleRecordMap()) #endif { memset(m_opcodeSamples, 0, sizeof(m_opcodeSamples)); @@ -210,7 +212,7 @@ namespace JSC { void setup(); void dump(ExecState*); - void notifyOfScope(ScopeNode* scope); + void notifyOfScope(ScriptExecutable* scope); void sample(CodeBlock* codeBlock, Instruction* vPC) { @@ -266,8 +268,8 @@ namespace JSC { unsigned m_opcodeSamplesInCTIFunctions[numOpcodeIDs]; #if ENABLE(CODEBLOCK_SAMPLING) - Mutex m_scopeSampleMapMutex; - OwnPtr<ScopeSampleRecordMap> m_scopeSampleMap; + Mutex m_scriptSampleMapMutex; + OwnPtr<ScriptSampleRecordMap> m_scopeSampleMap; #endif }; diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp index 59537b6..b0a0877 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.cpp @@ -256,15 +256,15 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d m_nextGlobalIndex -= symbolTable->size(); for (size_t i = 0; i < functionStack.size(); ++i) { - FuncDeclNode* funcDecl = functionStack[i]; - globalObject->removeDirect(funcDecl->m_ident); // Make sure our new function is not shadowed by an old property. - emitNewFunction(addGlobalVar(funcDecl->m_ident, false), funcDecl); + FunctionBodyNode* function = functionStack[i]; + globalObject->removeDirect(function->ident()); // Make sure our new function is not shadowed by an old property. + emitNewFunction(addGlobalVar(function->ident(), false), function); } Vector<RegisterID*, 32> newVars; for (size_t i = 0; i < varStack.size(); ++i) - if (!globalObject->hasProperty(exec, varStack[i].first)) - newVars.append(addGlobalVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant)); + if (!globalObject->hasProperty(exec, *varStack[i].first)) + newVars.append(addGlobalVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant)); preserveLastVar(); @@ -272,16 +272,16 @@ BytecodeGenerator::BytecodeGenerator(ProgramNode* programNode, const Debugger* d emitLoad(newVars[i], jsUndefined()); } else { for (size_t i = 0; i < functionStack.size(); ++i) { - FuncDeclNode* funcDecl = functionStack[i]; - globalObject->putWithAttributes(exec, funcDecl->m_ident, funcDecl->makeFunction(exec, scopeChain.node()), DontDelete); + FunctionBodyNode* function = functionStack[i]; + globalObject->putWithAttributes(exec, function->ident(), new (exec) JSFunction(exec, makeFunction(exec, function), scopeChain.node()), DontDelete); } for (size_t i = 0; i < varStack.size(); ++i) { - if (globalObject->hasProperty(exec, varStack[i].first)) + if (globalObject->hasProperty(exec, *varStack[i].first)) continue; int attributes = DontDelete; if (varStack[i].second & DeclarationStacks::IsConstant) attributes |= ReadOnly; - globalObject->putWithAttributes(exec, varStack[i].first, jsUndefined(), attributes); + globalObject->putWithAttributes(exec, *varStack[i].first, jsUndefined(), attributes); } preserveLastVar(); @@ -339,18 +339,18 @@ BytecodeGenerator::BytecodeGenerator(FunctionBodyNode* functionBody, const Debug const DeclarationStacks::FunctionStack& functionStack = functionBody->functionStack(); for (size_t i = 0; i < functionStack.size(); ++i) { - FuncDeclNode* funcDecl = functionStack[i]; - const Identifier& ident = funcDecl->m_ident; + FunctionBodyNode* function = functionStack[i]; + const Identifier& ident = function->ident(); m_functions.add(ident.ustring().rep()); - emitNewFunction(addVar(ident, false), funcDecl); + emitNewFunction(addVar(ident, false), function); } const DeclarationStacks::VarStack& varStack = functionBody->varStack(); for (size_t i = 0; i < varStack.size(); ++i) - addVar(varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant); + addVar(*varStack[i].first, varStack[i].second & DeclarationStacks::IsConstant); - const Identifier* parameters = functionBody->parameters(); - size_t parameterCount = functionBody->parameterCount(); + FunctionParameters& parameters = *functionBody->parameters(); + size_t parameterCount = parameters.size(); m_nextParameterIndex = -RegisterFile::CallFrameHeaderSize - parameterCount - 1; m_parameters.grow(1 + parameterCount); // reserve space for "this" @@ -397,6 +397,18 @@ BytecodeGenerator::BytecodeGenerator(EvalNode* evalNode, const Debugger* debugge codeBlock->setGlobalData(m_globalData); m_codeBlock->m_numParameters = 1; // Allocate space for "this" + const DeclarationStacks::FunctionStack& functionStack = evalNode->functionStack(); + for (size_t i = 0; i < functionStack.size(); ++i) + m_codeBlock->addFunctionDecl(makeFunction(m_globalData, functionStack[i])); + + const DeclarationStacks::VarStack& varStack = evalNode->varStack(); + unsigned numVariables = varStack.size(); + Vector<Identifier> variables; + variables.reserveCapacity(numVariables); + for (size_t i = 0; i < numVariables; ++i) + variables.append(*varStack[i].first); + codeBlock->adoptVariables(variables); + preserveLastVar(); } @@ -470,7 +482,8 @@ RegisterID* BytecodeGenerator::constRegisterFor(const Identifier& ident) return 0; SymbolTableEntry entry = symbolTable().get(ident.ustring().rep()); - ASSERT(!entry.isNull()); + if (entry.isNull()) + return 0; return ®isterFor(entry.getIndex()); } @@ -595,14 +608,15 @@ void ALWAYS_INLINE BytecodeGenerator::rewindUnaryOp() PassRefPtr<Label> BytecodeGenerator::emitJump(Label* target) { + size_t begin = instructions().size(); emitOpcode(target->isForward() ? op_jmp : op_loop); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* target) { - if (m_lastOpcodeID == op_less && !target->isForward()) { + if (m_lastOpcodeID == op_less) { int dstIndex; int src1Index; int src2Index; @@ -611,10 +625,12 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { rewindBinaryOp(); - emitOpcode(op_loop_if_less); + + size_t begin = instructions().size(); + emitOpcode(target->isForward() ? op_jless : op_loop_if_less); instructions().append(src1Index); instructions().append(src2Index); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } } else if (m_lastOpcodeID == op_lesseq && !target->isForward()) { @@ -626,10 +642,12 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { rewindBinaryOp(); + + size_t begin = instructions().size(); emitOpcode(op_loop_if_lesseq); instructions().append(src1Index); instructions().append(src2Index); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } } else if (m_lastOpcodeID == op_eq_null && target->isForward()) { @@ -640,9 +658,11 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { rewindUnaryOp(); + + size_t begin = instructions().size(); emitOpcode(op_jeq_null); instructions().append(srcIndex); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } } else if (m_lastOpcodeID == op_neq_null && target->isForward()) { @@ -653,24 +673,26 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfTrue(RegisterID* cond, Label* tar if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { rewindUnaryOp(); + + size_t begin = instructions().size(); emitOpcode(op_jneq_null); instructions().append(srcIndex); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } } + size_t begin = instructions().size(); + emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true); instructions().append(cond->index()); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* target) { - ASSERT(target->isForward()); - - if (m_lastOpcodeID == op_less) { + if (m_lastOpcodeID == op_less && target->isForward()) { int dstIndex; int src1Index; int src2Index; @@ -679,13 +701,15 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* ta if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { rewindBinaryOp(); + + size_t begin = instructions().size(); emitOpcode(op_jnless); instructions().append(src1Index); instructions().append(src2Index); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } - } else if (m_lastOpcodeID == op_lesseq) { + } else if (m_lastOpcodeID == op_lesseq && target->isForward()) { int dstIndex; int src1Index; int src2Index; @@ -694,10 +718,12 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* ta if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { rewindBinaryOp(); + + size_t begin = instructions().size(); emitOpcode(op_jnlesseq); instructions().append(src1Index); instructions().append(src2Index); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } } else if (m_lastOpcodeID == op_not) { @@ -708,12 +734,14 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* ta if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { rewindUnaryOp(); - emitOpcode(op_jtrue); + + size_t begin = instructions().size(); + emitOpcode(target->isForward() ? op_jtrue : op_loop_if_true); instructions().append(srcIndex); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } - } else if (m_lastOpcodeID == op_eq_null) { + } else if (m_lastOpcodeID == op_eq_null && target->isForward()) { int dstIndex; int srcIndex; @@ -721,12 +749,14 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* ta if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { rewindUnaryOp(); + + size_t begin = instructions().size(); emitOpcode(op_jneq_null); instructions().append(srcIndex); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } - } else if (m_lastOpcodeID == op_neq_null) { + } else if (m_lastOpcodeID == op_neq_null && target->isForward()) { int dstIndex; int srcIndex; @@ -734,49 +764,44 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpIfFalse(RegisterID* cond, Label* ta if (cond->index() == dstIndex && cond->isTemporary() && !cond->refCount()) { rewindUnaryOp(); + + size_t begin = instructions().size(); emitOpcode(op_jeq_null); instructions().append(srcIndex); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } } - emitOpcode(op_jfalse); + size_t begin = instructions().size(); + emitOpcode(target->isForward() ? op_jfalse : op_loop_if_false); instructions().append(cond->index()); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionCall(RegisterID* cond, Label* target) { + size_t begin = instructions().size(); + emitOpcode(op_jneq_ptr); instructions().append(cond->index()); instructions().append(m_scopeChain->globalObject()->d()->callFunction); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } PassRefPtr<Label> BytecodeGenerator::emitJumpIfNotFunctionApply(RegisterID* cond, Label* target) { + size_t begin = instructions().size(); + emitOpcode(op_jneq_ptr); instructions().append(cond->index()); instructions().append(m_scopeChain->globalObject()->d()->applyFunction); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } -unsigned BytecodeGenerator::addConstant(FuncDeclNode* n) -{ - // No need to explicitly unique function body nodes -- they're unique already. - return m_codeBlock->addFunction(n); -} - -unsigned BytecodeGenerator::addConstant(FuncExprNode* n) -{ - // No need to explicitly unique function expression nodes -- they're unique already. - return m_codeBlock->addFunctionExpression(n); -} - unsigned BytecodeGenerator::addConstant(const Identifier& ident) { UString::Rep* rep = ident.ustring().rep(); @@ -879,7 +904,7 @@ RegisterID* BytecodeGenerator::emitEqualityOp(OpcodeID opcodeID, RegisterID* dst && src1->isTemporary() && m_codeBlock->isConstantRegisterIndex(src2->index()) && m_codeBlock->constantRegister(src2->index()).jsValue().isString()) { - const UString& value = asString(m_codeBlock->constantRegister(src2->index()).jsValue())->value(); + const UString& value = asString(m_codeBlock->constantRegister(src2->index()).jsValue())->tryGetValue(); if (value == "undefined") { rewindUnaryOp(); emitOpcode(op_is_undefined); @@ -1254,6 +1279,19 @@ RegisterID* BytecodeGenerator::emitDeleteById(RegisterID* dst, RegisterID* base, RegisterID* BytecodeGenerator::emitGetByVal(RegisterID* dst, RegisterID* base, RegisterID* property) { + for (size_t i = m_forInContextStack.size(); i > 0; i--) { + ForInContext& context = m_forInContextStack[i - 1]; + if (context.propertyRegister == property) { + emitOpcode(op_get_by_pname); + instructions().append(dst->index()); + instructions().append(base->index()); + instructions().append(property->index()); + instructions().append(context.expectedSubscriptRegister->index()); + instructions().append(context.iterRegister->index()); + instructions().append(context.indexRegister->index()); + return dst; + } + } emitOpcode(op_get_by_val); instructions().append(dst->index()); instructions().append(base->index()); @@ -1313,11 +1351,13 @@ RegisterID* BytecodeGenerator::emitNewArray(RegisterID* dst, ElementNode* elemen return dst; } -RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FuncDeclNode* n) +RegisterID* BytecodeGenerator::emitNewFunction(RegisterID* dst, FunctionBodyNode* function) { + unsigned index = m_codeBlock->addFunctionDecl(makeFunction(m_globalData, function)); + emitOpcode(op_new_func); instructions().append(dst->index()); - instructions().append(addConstant(n)); + instructions().append(index); return dst; } @@ -1332,9 +1372,12 @@ RegisterID* BytecodeGenerator::emitNewRegExp(RegisterID* dst, RegExp* regExp) RegisterID* BytecodeGenerator::emitNewFunctionExpression(RegisterID* r0, FuncExprNode* n) { + FunctionBodyNode* function = n->body(); + unsigned index = m_codeBlock->addFunctionExpr(makeFunction(m_globalData, function)); + emitOpcode(op_new_func_exp); instructions().append(r0->index()); - instructions().append(addConstant(n)); + instructions().append(index); return r0; } @@ -1712,6 +1755,8 @@ PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, Contro } if (nNormalScopes) { + size_t begin = instructions().size(); + // We need to remove a number of dynamic scopes to get to the next // finally block emitOpcode(op_jmp_scopes); @@ -1720,14 +1765,14 @@ PassRefPtr<Label> BytecodeGenerator::emitComplexJumpScopes(Label* target, Contro // If topScope == bottomScope then there isn't actually a finally block // left to emit, so make the jmp_scopes jump directly to the target label if (topScope == bottomScope) { - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } // Otherwise we just use jmp_scopes to pop a group of scopes and go // to the next instruction RefPtr<Label> nextInsn = newLabel(); - instructions().append(nextInsn->offsetFrom(instructions().size())); + instructions().append(nextInsn->bind(begin, instructions().size())); emitLabel(nextInsn.get()); } @@ -1752,27 +1797,47 @@ PassRefPtr<Label> BytecodeGenerator::emitJumpScopes(Label* target, int targetSco if (m_finallyDepth) return emitComplexJumpScopes(target, &m_scopeContextStack.last(), &m_scopeContextStack.last() - scopeDelta); + size_t begin = instructions().size(); + emitOpcode(op_jmp_scopes); instructions().append(scopeDelta); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return target; } -RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* iter, Label* target) +RegisterID* BytecodeGenerator::emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget) { + size_t begin = instructions().size(); + + emitOpcode(op_get_pnames); + instructions().append(dst->index()); + instructions().append(base->index()); + instructions().append(i->index()); + instructions().append(size->index()); + instructions().append(breakTarget->bind(begin, instructions().size())); + return dst; +} + +RegisterID* BytecodeGenerator::emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target) +{ + size_t begin = instructions().size(); + emitOpcode(op_next_pname); instructions().append(dst->index()); + instructions().append(base->index()); + instructions().append(i->index()); + instructions().append(size->index()); instructions().append(iter->index()); - instructions().append(target->offsetFrom(instructions().size())); + instructions().append(target->bind(begin, instructions().size())); return dst; } RegisterID* BytecodeGenerator::emitCatch(RegisterID* targetRegister, Label* start, Label* end) { #if ENABLE(JIT) - HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() }; + HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth, CodeLocationLabel() }; #else - HandlerInfo info = { start->offsetFrom(0), end->offsetFrom(0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth }; + HandlerInfo info = { start->bind(0, 0), end->bind(0, 0), instructions().size(), m_dynamicScopeDepth + m_baseScopeDepth }; #endif m_codeBlock->addExceptionHandler(info); @@ -1792,9 +1857,11 @@ RegisterID* BytecodeGenerator::emitNewError(RegisterID* dst, ErrorType type, JSV PassRefPtr<Label> BytecodeGenerator::emitJumpSubroutine(RegisterID* retAddrDst, Label* finally) { + size_t begin = instructions().size(); + emitOpcode(op_jsr); instructions().append(retAddrDst->index()); - instructions().append(finally->offsetFrom(instructions().size())); + instructions().append(finally->bind(begin, instructions().size())); emitLabel(newLabel().get()); // Record the fact that the next instruction is implicitly labeled, because op_sret will return to it. return finally; } @@ -1805,7 +1872,7 @@ void BytecodeGenerator::emitSubroutineReturn(RegisterID* retAddrSrc) instructions().append(retAddrSrc->index()); } -void BytecodeGenerator::emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value) +void BytecodeGenerator::emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value) { ControlFlowContext context; context.isFinallyBlock = false; @@ -1864,7 +1931,7 @@ static void prepareJumpTableForImmediateSwitch(SimpleJumpTable& jumpTable, int32 // We're emitting this after the clause labels should have been fixed, so // the labels should not be "forward" references ASSERT(!labels[i]->isForward()); - jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress)); + jumpTable.add(keyForImmediateSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3)); } } @@ -1890,7 +1957,7 @@ static void prepareJumpTableForCharacterSwitch(SimpleJumpTable& jumpTable, int32 // We're emitting this after the clause labels should have been fixed, so // the labels should not be "forward" references ASSERT(!labels[i]->isForward()); - jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->offsetFrom(switchAddress)); + jumpTable.add(keyForCharacterSwitch(nodes[i], min, max), labels[i]->bind(switchAddress, switchAddress + 3)); } } @@ -1904,7 +1971,7 @@ static void prepareJumpTableForStringSwitch(StringJumpTable& jumpTable, int32_t ASSERT(nodes[i]->isString()); UString::Rep* clause = static_cast<StringNode*>(nodes[i])->value().ustring().rep(); OffsetLocation location; - location.branchOffset = labels[i]->offsetFrom(switchAddress); + location.branchOffset = labels[i]->bind(switchAddress, switchAddress + 3); jumpTable.offsetTable.add(clause, location); } } @@ -1915,23 +1982,23 @@ void BytecodeGenerator::endSwitch(uint32_t clauseCount, RefPtr<Label>* labels, E m_switchContextStack.removeLast(); if (switchInfo.switchType == SwitchInfo::SwitchImmediate) { instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfImmediateSwitchJumpTables(); - instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.bytecodeOffset + 3); + instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); SimpleJumpTable& jumpTable = m_codeBlock->addImmediateSwitchJumpTable(); - prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.bytecodeOffset + 3, clauseCount, labels, nodes, min, max); + prepareJumpTableForImmediateSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max); } else if (switchInfo.switchType == SwitchInfo::SwitchCharacter) { instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfCharacterSwitchJumpTables(); - instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.bytecodeOffset + 3); + instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); SimpleJumpTable& jumpTable = m_codeBlock->addCharacterSwitchJumpTable(); - prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.bytecodeOffset + 3, clauseCount, labels, nodes, min, max); + prepareJumpTableForCharacterSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes, min, max); } else { ASSERT(switchInfo.switchType == SwitchInfo::SwitchString); instructions()[switchInfo.bytecodeOffset + 1] = m_codeBlock->numberOfStringSwitchJumpTables(); - instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->offsetFrom(switchInfo.bytecodeOffset + 3); + instructions()[switchInfo.bytecodeOffset + 2] = defaultLabel->bind(switchInfo.bytecodeOffset, switchInfo.bytecodeOffset + 3); StringJumpTable& jumpTable = m_codeBlock->addStringSwitchJumpTable(); - prepareJumpTableForStringSwitch(jumpTable, switchInfo.bytecodeOffset + 3, clauseCount, labels, nodes); + prepareJumpTableForStringSwitch(jumpTable, switchInfo.bytecodeOffset, clauseCount, labels, nodes); } } diff --git a/JavaScriptCore/bytecompiler/BytecodeGenerator.h b/JavaScriptCore/bytecompiler/BytecodeGenerator.h index c273597..8b6a425 100644 --- a/JavaScriptCore/bytecompiler/BytecodeGenerator.h +++ b/JavaScriptCore/bytecompiler/BytecodeGenerator.h @@ -61,7 +61,14 @@ namespace JSC { FinallyContext finallyContext; }; - class BytecodeGenerator : public WTF::FastAllocBase { + struct ForInContext { + RefPtr<RegisterID> expectedSubscriptRegister; + RefPtr<RegisterID> iterRegister; + RefPtr<RegisterID> indexRegister; + RefPtr<RegisterID> propertyRegister; + }; + + class BytecodeGenerator : public FastAllocBase { public: typedef DeclarationStacks::VarStack VarStack; typedef DeclarationStacks::FunctionStack FunctionStack; @@ -185,6 +192,19 @@ namespace JSC { return emitNode(0, n); } + void emitNodeInConditionContext(ExpressionNode* n, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) + { + if (!m_codeBlock->numberOfLineInfos() || m_codeBlock->lastLineInfo().lineNumber != n->lineNo()) { + LineInfo info = { instructions().size(), n->lineNo() }; + m_codeBlock->addLineInfo(info); + } + if (m_emitNodeDepth >= s_maxEmitNodeDepth) + emitThrowExpressionTooDeepException(); + ++m_emitNodeDepth; + n->emitBytecodeInConditionContext(*this, trueTarget, falseTarget, fallThroughMeansTrue); + --m_emitNodeDepth; + } + void emitExpressionInfo(unsigned divot, unsigned startOffset, unsigned endOffset) { divot -= m_codeBlock->sourceOffset(); @@ -254,7 +274,7 @@ namespace JSC { RegisterID* emitNewObject(RegisterID* dst); RegisterID* emitNewArray(RegisterID* dst, ElementNode*); // stops at first elision - RegisterID* emitNewFunction(RegisterID* dst, FuncDeclNode* func); + RegisterID* emitNewFunction(RegisterID* dst, FunctionBodyNode* body); RegisterID* emitNewFunctionExpression(RegisterID* dst, FuncExprNode* func); RegisterID* emitNewRegExp(RegisterID* dst, RegExp* regExp); @@ -312,13 +332,13 @@ namespace JSC { PassRefPtr<Label> emitJumpSubroutine(RegisterID* retAddrDst, Label*); void emitSubroutineReturn(RegisterID* retAddrSrc); - RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base) { return emitUnaryOp(op_get_pnames, dst, base); } - RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* iter, Label* target); + RegisterID* emitGetPropertyNames(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, Label* breakTarget); + RegisterID* emitNextPropertyName(RegisterID* dst, RegisterID* base, RegisterID* i, RegisterID* size, RegisterID* iter, Label* target); RegisterID* emitCatch(RegisterID*, Label* start, Label* end); void emitThrow(RegisterID* exc) { emitUnaryNoDstOp(op_throw, exc); } RegisterID* emitNewError(RegisterID* dst, ErrorType type, JSValue message); - void emitPushNewScope(RegisterID* dst, Identifier& property, RegisterID* value); + void emitPushNewScope(RegisterID* dst, const Identifier& property, RegisterID* value); RegisterID* emitPushScope(RegisterID* scope); void emitPopScope(); @@ -331,6 +351,17 @@ namespace JSC { void pushFinallyContext(Label* target, RegisterID* returnAddrDst); void popFinallyContext(); + void pushOptimisedForIn(RegisterID* expectedBase, RegisterID* iter, RegisterID* index, RegisterID* propertyRegister) + { + ForInContext context = { expectedBase, iter, index, propertyRegister }; + m_forInContextStack.append(context); + } + + void popOptimisedForIn() + { + m_forInContextStack.removeLast(); + } + LabelScope* breakTarget(const Identifier&); LabelScope* continueTarget(const Identifier&); @@ -413,12 +444,20 @@ namespace JSC { return m_globals[-index - 1]; } - unsigned addConstant(FuncDeclNode*); - unsigned addConstant(FuncExprNode*); unsigned addConstant(const Identifier&); RegisterID* addConstantValue(JSValue); unsigned addRegExp(RegExp*); + PassRefPtr<FunctionExecutable> makeFunction(ExecState* exec, FunctionBodyNode* body) + { + return FunctionExecutable::create(exec, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); + } + + PassRefPtr<FunctionExecutable> makeFunction(JSGlobalData* globalData, FunctionBodyNode* body) + { + return FunctionExecutable::create(globalData, body->ident(), body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); + } + Vector<Instruction>& instructions() { return m_codeBlock->instructions(); } SymbolTable& symbolTable() { return *m_symbolTable; } @@ -445,12 +484,12 @@ namespace JSC { RegisterID m_thisRegister; RegisterID m_argumentsRegister; int m_activationRegisterIndex; - WTF::SegmentedVector<RegisterID, 32> m_constantPoolRegisters; - WTF::SegmentedVector<RegisterID, 32> m_calleeRegisters; - WTF::SegmentedVector<RegisterID, 32> m_parameters; - WTF::SegmentedVector<RegisterID, 32> m_globals; - WTF::SegmentedVector<Label, 32> m_labels; - WTF::SegmentedVector<LabelScope, 8> m_labelScopes; + SegmentedVector<RegisterID, 32> m_constantPoolRegisters; + SegmentedVector<RegisterID, 32> m_calleeRegisters; + SegmentedVector<RegisterID, 32> m_parameters; + SegmentedVector<RegisterID, 32> m_globals; + SegmentedVector<Label, 32> m_labels; + SegmentedVector<LabelScope, 8> m_labelScopes; RefPtr<RegisterID> m_lastVar; int m_finallyDepth; int m_dynamicScopeDepth; @@ -459,6 +498,7 @@ namespace JSC { Vector<ControlFlowContext> m_scopeContextStack; Vector<SwitchInfo> m_switchContextStack; + Vector<ForInContext> m_forInContextStack; int m_nextGlobalIndex; int m_nextParameterIndex; diff --git a/JavaScriptCore/bytecompiler/Label.h b/JavaScriptCore/bytecompiler/Label.h index 0b3d038..8cab1db 100644 --- a/JavaScriptCore/bytecompiler/Label.h +++ b/JavaScriptCore/bytecompiler/Label.h @@ -51,19 +51,17 @@ namespace JSC { m_location = location; unsigned size = m_unresolvedJumps.size(); - for (unsigned i = 0; i < size; ++i) { - unsigned j = m_unresolvedJumps[i]; - m_codeBlock->instructions()[j].u.operand = m_location - j; - } + for (unsigned i = 0; i < size; ++i) + m_codeBlock->instructions()[m_unresolvedJumps[i].second].u.operand = m_location - m_unresolvedJumps[i].first; } - int offsetFrom(int location) const + int bind(int opcode, int offset) const { if (m_location == invalidLocation) { - m_unresolvedJumps.append(location); + m_unresolvedJumps.append(std::make_pair(opcode, offset)); return 0; } - return m_location - location; + return m_location - opcode; } void ref() { ++m_refCount; } @@ -77,7 +75,7 @@ namespace JSC { bool isForward() const { return m_location == invalidLocation; } private: - typedef Vector<int, 8> JumpVector; + typedef Vector<std::pair<int, int>, 8> JumpVector; static const unsigned invalidLocation = UINT_MAX; diff --git a/JavaScriptCore/bytecompiler/NodesCodegen.cpp b/JavaScriptCore/bytecompiler/NodesCodegen.cpp new file mode 100644 index 0000000..80a7a2f --- /dev/null +++ b/JavaScriptCore/bytecompiler/NodesCodegen.cpp @@ -0,0 +1,2002 @@ +/* +* Copyright (C) 1999-2002 Harri Porten (porten@kde.org) +* Copyright (C) 2001 Peter Kelly (pmk@post.com) +* Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. +* Copyright (C) 2007 Cameron Zwarich (cwzwarich@uwaterloo.ca) +* Copyright (C) 2007 Maks Orlovich +* Copyright (C) 2007 Eric Seidel <eric@webkit.org> +* +* This library is free software; you can redistribute it and/or +* modify it under the terms of the GNU Library General Public +* License as published by the Free Software Foundation; either +* version 2 of the License, or (at your option) any later version. +* +* This library is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* Library General Public License for more details. +* +* You should have received a copy of the GNU Library General Public License +* along with this library; see the file COPYING.LIB. If not, write to +* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, +* Boston, MA 02110-1301, USA. +* +*/ + +#include "config.h" +#include "Nodes.h" +#include "NodeConstructors.h" + +#include "BytecodeGenerator.h" +#include "CallFrame.h" +#include "Debugger.h" +#include "JIT.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" +#include "JSStaticScopeObject.h" +#include "LabelScope.h" +#include "Lexer.h" +#include "Operations.h" +#include "Parser.h" +#include "PropertyNameArray.h" +#include "RegExpObject.h" +#include "SamplingTool.h" +#include <wtf/Assertions.h> +#include <wtf/RefCountedLeakCounter.h> +#include <wtf/Threading.h> + +using namespace WTF; + +namespace JSC { + +/* + Details of the emitBytecode function. + + 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. + + The dst argument provides for a crude form of copy propagation. For example, + + x = 1 + + becomes + + load r[x], 1 + + instead of + + load r0, 1 + mov r[x], r0 + + because the assignment node, "x =", passes r[x] as dst to the number node, "1". +*/ + +// ------------------------------ ThrowableExpressionData -------------------------------- + +static void substitute(UString& string, const UString& substring) +{ + int position = string.find("%s"); + ASSERT(position != -1); + UString newString = string.substr(0, position); + newString.append(substring); + newString.append(string.substr(position + 2)); + string = newString; +} + +RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* message) +{ + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message)); + generator.emitThrow(exception); + return exception; +} + +RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const UString& label) +{ + UString message = messageTemplate; + substitute(message, label); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* exception = generator.emitNewError(generator.newTemporary(), type, jsString(generator.globalData(), message)); + generator.emitThrow(exception); + return exception; +} + +inline RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType type, const char* messageTemplate, const Identifier& label) +{ + return emitThrowError(generator, type, messageTemplate, label.ustring()); +} + +// ------------------------------ NullNode ------------------------------------- + +RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, jsNull()); +} + +// ------------------------------ BooleanNode ---------------------------------- + +RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, m_value); +} + +// ------------------------------ NumberNode ----------------------------------- + +RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, m_value); +} + +// ------------------------------ StringNode ----------------------------------- + +RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.emitLoad(dst, m_value); +} + +// ------------------------------ RegExpNode ----------------------------------- + +RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegExp> regExp = RegExp::create(generator.globalData(), m_pattern.ustring(), m_flags.ustring()); + if (!regExp->isValid()) + return emitThrowError(generator, SyntaxError, "Invalid regular expression: %s", regExp->errorMessage()); + if (dst == generator.ignoredResult()) + return 0; + return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); +} + +// ------------------------------ ThisNode ------------------------------------- + +RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + return 0; + return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); +} + +// ------------------------------ ResolveNode ---------------------------------- + +bool ResolveNode::isPure(BytecodeGenerator& generator) const +{ + return generator.isLocal(m_ident); +} + +RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (dst == generator.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); +} + +// ------------------------------ ArrayNode ------------------------------------ + +RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + // FIXME: Should we put all of this code into emitNewArray? + + unsigned length = 0; + ElementNode* firstPutElement; + for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { + if (firstPutElement->elision()) + break; + ++length; + } + + if (!firstPutElement && !m_elision) + return generator.emitNewArray(generator.finalDestination(dst), m_element); + + RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element); + + 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_elision) { + RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length)); + generator.emitPutById(array.get(), generator.propertyNames().length, value); + } + + return generator.moveToDestinationIfNeeded(dst, array.get()); +} + +bool ArrayNode::isSimpleArray() const +{ + if (m_elision || m_optional) + return false; + for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { + if (ptr->elision()) + return false; + } + return true; +} + +ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const +{ + ASSERT(!m_elision && !m_optional); + ElementNode* ptr = m_element; + if (!ptr) + return 0; + ArgumentListNode* head = new (globalData) ArgumentListNode(globalData, ptr->value()); + ArgumentListNode* tail = head; + ptr = ptr->next(); + for (; ptr; ptr = ptr->next()) { + ASSERT(!ptr->elision()); + tail = new (globalData) ArgumentListNode(globalData, tail, ptr->value()); + } + return head; +} + +// ------------------------------ ObjectLiteralNode ---------------------------- + +RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (!m_list) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitNewObject(generator.finalDestination(dst)); + } + return generator.emitNode(dst, m_list); +} + +// ------------------------------ PropertyListNode ----------------------------- + +RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> newObj = generator.tempDestination(dst); + + generator.emitNewObject(newObj.get()); + + for (PropertyListNode* p = this; p; p = p->m_next) { + RegisterID* value = generator.emitNode(p->m_node->m_assign); + + switch (p->m_node->m_type) { + case PropertyNode::Constant: { + generator.emitPutById(newObj.get(), p->m_node->name(), value); + break; + } + case PropertyNode::Getter: { + generator.emitPutGetter(newObj.get(), p->m_node->name(), value); + break; + } + case PropertyNode::Setter: { + generator.emitPutSetter(newObj.get(), p->m_node->name(), value); + break; + } + default: + ASSERT_NOT_REACHED(); + } + } + + return generator.moveToDestinationIfNeeded(dst, newObj.get()); +} + +// ------------------------------ BracketAccessorNode -------------------------------- + +RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); + RegisterID* property = generator.emitNode(m_subscript); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); +} + +// ------------------------------ DotAccessorNode -------------------------------- + +RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* base = generator.emitNode(m_base); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitGetById(generator.finalDestination(dst), base, m_ident); +} + +// ------------------------------ ArgumentListNode ----------------------------- + +RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ASSERT(m_expr); + return generator.emitNode(dst, m_expr); +} + +// ------------------------------ NewExprNode ---------------------------------- + +RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> func = generator.emitNode(m_expr); + return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args, divot(), startOffset(), endOffset()); +} + +// ------------------------------ EvalFunctionCallNode ---------------------------------- + +RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> func = generator.tempDestination(dst); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); + generator.emitResolveWithBase(thisRegister.get(), func.get(), generator.propertyNames().eval); + return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallValueNode ---------------------------------- + +RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> func = generator.emitNode(m_expr); + RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallResolveNode ---------------------------------- + +RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) { + RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, thisRegister.get()), local.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + } + + 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); + RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + } + + RefPtr<RegisterID> func = generator.newTemporary(); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + int identifierStart = divot() - startOffset(); + generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0); + generator.emitResolveWithBase(thisRegister.get(), func.get(), m_ident); + return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallBracketNode ---------------------------------- + +RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + RegisterID* property = generator.emitNode(m_subscript); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property); + RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); + return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); +} + +// ------------------------------ FunctionCallDotNode ---------------------------------- + +RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> function = generator.tempDestination(dst); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + generator.emitNode(thisRegister.get(), m_base); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + generator.emitMethodCheck(); + generator.emitGetById(function.get(), thisRegister.get(), m_ident); + return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); +} + +RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<Label> realCall = generator.newLabel(); + RefPtr<Label> end = generator.newLabel(); + RefPtr<RegisterID> base = generator.emitNode(m_base); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); + RefPtr<RegisterID> finalDestination = generator.finalDestination(dst, function.get()); + generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); + { + RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + ArgumentListNode* oldList = m_args->m_listNode; + if (m_args->m_listNode && m_args->m_listNode->m_expr) { + generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); + m_args->m_listNode = m_args->m_listNode->m_next; + } else + generator.emitLoad(thisRegister.get(), jsNull()); + + generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + generator.emitJump(end.get()); + m_args->m_listNode = oldList; + } + generator.emitLabel(realCall.get()); + { + RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); + generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + } + generator.emitLabel(end.get()); + return finalDestination.get(); +} + +static bool areTrivialApplyArguments(ArgumentsNode* args) +{ + return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next + || (!args->m_listNode->m_next->m_next && args->m_listNode->m_next->m_expr->isSimpleArray()); +} + +RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + // A few simple cases can be trivially handled as ordinary function calls. + // function.apply(), function.apply(arg) -> identical to function.call + // function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation + bool mayBeCall = areTrivialApplyArguments(m_args); + + RefPtr<Label> realCall = generator.newLabel(); + RefPtr<Label> end = generator.newLabel(); + RefPtr<RegisterID> base = generator.emitNode(m_base); + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); + RefPtr<RegisterID> finalDestination = generator.finalDestination(dst, function.get()); + generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); + { + if (mayBeCall) { + RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + ArgumentListNode* oldList = m_args->m_listNode; + if (m_args->m_listNode && m_args->m_listNode->m_expr) { + generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); + m_args->m_listNode = m_args->m_listNode->m_next; + if (m_args->m_listNode) { + ASSERT(m_args->m_listNode->m_expr->isSimpleArray()); + ASSERT(!m_args->m_listNode->m_next); + m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_expr)->toArgumentList(generator.globalData()); + } + } else + generator.emitLoad(thisRegister.get(), jsNull()); + generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + m_args->m_listNode = oldList; + } else { + ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); + RefPtr<RegisterID> realFunction = generator.emitMove(generator.newTemporary(), base.get()); + RefPtr<RegisterID> argsCountRegister = generator.newTemporary(); + RefPtr<RegisterID> thisRegister = generator.newTemporary(); + RefPtr<RegisterID> argsRegister = generator.newTemporary(); + generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); + ArgumentListNode* args = m_args->m_listNode->m_next; + bool isArgumentsApply = false; + if (args->m_expr->isResolveNode()) { + ResolveNode* resolveNode = static_cast<ResolveNode*>(args->m_expr); + isArgumentsApply = generator.willResolveToArguments(resolveNode->identifier()); + if (isArgumentsApply) + generator.emitMove(argsRegister.get(), generator.uncheckedRegisterForArguments()); + } + if (!isArgumentsApply) + generator.emitNode(argsRegister.get(), args->m_expr); + while ((args = args->m_next)) + generator.emitNode(args->m_expr); + + generator.emitLoadVarargs(argsCountRegister.get(), argsRegister.get()); + generator.emitCallVarargs(finalDestination.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset()); + } + generator.emitJump(end.get()); + } + generator.emitLabel(realCall.get()); + { + RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); + generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); + } + generator.emitLabel(end.get()); + return finalDestination.get(); +} + +// ------------------------------ PostfixResolveNode ---------------------------------- + +static RegisterID* emitPreIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) +{ + return (oper == OpPlusPlus) ? generator.emitPreInc(srcDst) : generator.emitPreDec(srcDst); +} + +static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) +{ + if (srcDst == dst) + return generator.emitToJSNumber(dst, srcDst); + return (oper == OpPlusPlus) ? generator.emitPostInc(dst, srcDst) : generator.emitPostDec(dst, srcDst); +} + +RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitToJSNumber(generator.finalDestination(dst), local); + } + + if (dst == generator.ignoredResult()) + return emitPreIncOrDec(generator, local, m_operator); + return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator); + } + + 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 == generator.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; + } + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RefPtr<RegisterID> value = generator.newTemporary(); + RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); + RegisterID* oldValue; + if (dst == generator.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 ---------------------------------- + +RegisterID* PostfixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + RefPtr<RegisterID> property = generator.emitNode(m_subscript); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); + RegisterID* oldValue; + if (dst == generator.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(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), value.get()); + return oldValue; +} + +// ------------------------------ PostfixDotNode ---------------------------------- + +RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); + RegisterID* oldValue; + if (dst == generator.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(divot(), startOffset(), endOffset()); + generator.emitPutById(base.get(), m_ident, value.get()); + return oldValue; +} + +// ------------------------------ PostfixErrorNode ----------------------------------- + +RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + 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 ----------------------------------- + +RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (generator.registerFor(m_ident)) + return generator.emitLoad(generator.finalDestination(dst), false); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident); + return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); +} + +// ------------------------------ DeleteBracketNode ----------------------------------- + +RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> r0 = generator.emitNode(m_base); + RegisterID* r1 = generator.emitNode(m_subscript); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1); +} + +// ------------------------------ DeleteDotNode ----------------------------------- + +RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* r0 = generator.emitNode(m_base); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident); +} + +// ------------------------------ DeleteValueNode ----------------------------------- + +RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitNode(generator.ignoredResult(), m_expr); + + // delete on a non-location expression ignores the value and returns true + return generator.emitLoad(generator.finalDestination(dst), true); +} + +// ------------------------------ VoidNode ------------------------------------- + +RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) { + generator.emitNode(generator.ignoredResult(), m_expr); + return 0; + } + RefPtr<RegisterID> r0 = generator.emitNode(m_expr); + return generator.emitLoad(dst, jsUndefined()); +} + +// ------------------------------ TypeOfValueNode ----------------------------------- + +RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + return generator.emitTypeOf(generator.finalDestination(dst), local); + } + + RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident); + generator.emitGetById(scratch.get(), scratch.get(), m_ident); + if (dst == generator.ignoredResult()) + return 0; + return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get()); +} + +// ------------------------------ TypeOfValueNode ----------------------------------- + +RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) { + generator.emitNode(generator.ignoredResult(), m_expr); + return 0; + } + RefPtr<RegisterID> src = generator.emitNode(m_expr); + return generator.emitTypeOf(generator.finalDestination(dst), src.get()); +} + +// ------------------------------ PrefixResolveNode ---------------------------------- + +RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) { + if (dst == generator.ignoredResult()) + return 0; + RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0); + return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes()); + } + + emitPreIncOrDec(generator, local, m_operator); + return generator.moveToDestinationIfNeeded(dst, local); + } + + 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()); + } + + generator.emitExpressionInfo(divot(), startOffset(), 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 ---------------------------------- + +RegisterID* PrefixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + RefPtr<RegisterID> property = generator.emitNode(m_subscript); + RefPtr<RegisterID> propDst = generator.tempDestination(dst); + + generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, 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(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), value); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); +} + +// ------------------------------ PrefixDotNode ---------------------------------- + +RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNode(m_base); + RefPtr<RegisterID> propDst = generator.tempDestination(dst); + + generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, 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(divot(), startOffset(), endOffset()); + generator.emitPutById(base.get(), m_ident, value); + return generator.moveToDestinationIfNeeded(dst, propDst.get()); +} + +// ------------------------------ PrefixErrorNode ----------------------------------- + +RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + 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."); +} + +// ------------------------------ Unary Operation Nodes ----------------------------------- + +RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RegisterID* src = generator.emitNode(m_expr); + return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src); +} + + +// ------------------------------ LogicalNotNode ----------------------------------- + +void LogicalNotNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) +{ + ASSERT(expr()->hasConditionContextCodegen()); + + // reverse the true and false targets + generator.emitNodeInConditionContext(expr(), falseTarget, trueTarget, !fallThroughMeansTrue); +} + + +// ------------------------------ Binary Operation Nodes ----------------------------------- + +// BinaryOpNode::emitStrcat: +// +// This node generates an op_strcat operation. This opcode can handle concatenation of three or +// more values, where we can determine a set of separate op_add operations would be operating on +// string values. +// +// This function expects to be operating on a graph of AST nodes looking something like this: +// +// (a)... (b) +// \ / +// (+) (c) +// \ / +// [d] ((+)) +// \ / +// [+=] +// +// The assignment operation is optional, if it exists the register holding the value on the +// lefthand side of the assignment should be passing as the optional 'lhs' argument. +// +// The method should be called on the node at the root of the tree of regular binary add +// operations (marked in the diagram with a double set of parentheses). This node must +// be performing a string concatenation (determined by statically detecting that at least +// one child must be a string). +// +// Since the minimum number of values being concatenated together is expected to be 3, if +// a lhs to a concatenating assignment is not provided then the root add should have at +// least one left child that is also an add that can be determined to be operating on strings. +// +RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs, ReadModifyResolveNode* emitExpressionInfoForMe) +{ + ASSERT(isAdd()); + ASSERT(resultDescriptor().definitelyIsString()); + + // Create a list of expressions for all the adds in the tree of nodes we can convert into + // a string concatenation. The rightmost node (c) is added first. The rightmost node is + // added first, and the leftmost child is never added, so the vector produced for the + // example above will be [ c, b ]. + Vector<ExpressionNode*, 16> reverseExpressionList; + reverseExpressionList.append(m_expr2); + + // Examine the left child of the add. So long as this is a string add, add its right-child + // to the list, and keep processing along the left fork. + ExpressionNode* leftMostAddChild = m_expr1; + while (leftMostAddChild->isAdd() && leftMostAddChild->resultDescriptor().definitelyIsString()) { + reverseExpressionList.append(static_cast<AddNode*>(leftMostAddChild)->m_expr2); + leftMostAddChild = static_cast<AddNode*>(leftMostAddChild)->m_expr1; + } + + Vector<RefPtr<RegisterID>, 16> temporaryRegisters; + + // If there is an assignment, allocate a temporary to hold the lhs after conversion. + // We could possibly avoid this (the lhs is converted last anyway, we could let the + // op_strcat node handle its conversion if required). + if (lhs) + temporaryRegisters.append(generator.newTemporary()); + + // Emit code for the leftmost node ((a) in the example). + temporaryRegisters.append(generator.newTemporary()); + RegisterID* leftMostAddChildTempRegister = temporaryRegisters.last().get(); + generator.emitNode(leftMostAddChildTempRegister, leftMostAddChild); + + // Note on ordering of conversions: + // + // We maintain the same ordering of conversions as we would see if the concatenations + // was performed as a sequence of adds (otherwise this optimization could change + // behaviour should an object have been provided a valueOf or toString method). + // + // Considering the above example, the sequnce of execution is: + // * evaluate operand (a) + // * evaluate operand (b) + // * convert (a) to primitive <- (this would be triggered by the first add) + // * convert (b) to primitive <- (ditto) + // * evaluate operand (c) + // * convert (c) to primitive <- (this would be triggered by the second add) + // And optionally, if there is an assignment: + // * convert (d) to primitive <- (this would be triggered by the assigning addition) + // + // As such we do not plant an op to convert the leftmost child now. Instead, use + // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion + // once the second node has been generated. However, if the leftmost child is an + // immediate we can trivially determine that no conversion will be required. + // If this is the case + if (leftMostAddChild->isString()) + leftMostAddChildTempRegister = 0; + + while (reverseExpressionList.size()) { + ExpressionNode* node = reverseExpressionList.last(); + reverseExpressionList.removeLast(); + + // Emit the code for the current node. + temporaryRegisters.append(generator.newTemporary()); + generator.emitNode(temporaryRegisters.last().get(), node); + + // On the first iteration of this loop, when we first reach this point we have just + // generated the second node, which means it is time to convert the leftmost operand. + if (leftMostAddChildTempRegister) { + generator.emitToPrimitive(leftMostAddChildTempRegister, leftMostAddChildTempRegister); + leftMostAddChildTempRegister = 0; // Only do this once. + } + // Plant a conversion for this node, if necessary. + if (!node->isString()) + generator.emitToPrimitive(temporaryRegisters.last().get(), temporaryRegisters.last().get()); + } + ASSERT(temporaryRegisters.size() >= 3); + + // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. + // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. + if (emitExpressionInfoForMe) + generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); + + // If there is an assignment convert the lhs now. This will also copy lhs to + // the temporary register we allocated for it. + if (lhs) + generator.emitToPrimitive(temporaryRegisters[0].get(), lhs); + + return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); +} + +RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + OpcodeID opcodeID = this->opcodeID(); + + if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) + return emitStrcat(generator, dst); + + if (opcodeID == op_neq) { + if (m_expr1->isNull() || m_expr2->isNull()) { + RefPtr<RegisterID> src = generator.tempDestination(dst); + generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); + return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get()); + } + } + + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + return generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); +} + +RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (m_expr1->isNull() || m_expr2->isNull()) { + RefPtr<RegisterID> src = generator.tempDestination(dst); + generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); + return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get()); + } + + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2); +} + +RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2); +} + +RegisterID* ReverseBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src2, src1.get(), OperandTypes(m_expr2->resultDescriptor(), m_expr1->resultDescriptor())); +} + +RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); + RegisterID* src2 = generator.emitNode(m_expr2); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); +} + +RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); + RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitGetByIdExceptionInfo(op_instanceof); + RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype); +} + +// ------------------------------ LogicalOpNode ---------------------------- + +RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> temp = generator.tempDestination(dst); + RefPtr<Label> target = generator.newLabel(); + + generator.emitNode(temp.get(), m_expr1); + if (m_operator == OpLogicalAnd) + generator.emitJumpIfFalse(temp.get(), target.get()); + else + generator.emitJumpIfTrue(temp.get(), target.get()); + generator.emitNode(temp.get(), m_expr2); + generator.emitLabel(target.get()); + + return generator.moveToDestinationIfNeeded(dst, temp.get()); +} + +void LogicalOpNode::emitBytecodeInConditionContext(BytecodeGenerator& generator, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue) +{ + if (m_expr1->hasConditionContextCodegen()) { + RefPtr<Label> afterExpr1 = generator.newLabel(); + if (m_operator == OpLogicalAnd) + generator.emitNodeInConditionContext(m_expr1, afterExpr1.get(), falseTarget, true); + else + generator.emitNodeInConditionContext(m_expr1, trueTarget, afterExpr1.get(), false); + generator.emitLabel(afterExpr1.get()); + } else { + RegisterID* temp = generator.emitNode(m_expr1); + if (m_operator == OpLogicalAnd) + generator.emitJumpIfFalse(temp, falseTarget); + else + generator.emitJumpIfTrue(temp, trueTarget); + } + + if (m_expr2->hasConditionContextCodegen()) + generator.emitNodeInConditionContext(m_expr2, trueTarget, falseTarget, fallThroughMeansTrue); + else { + RegisterID* temp = generator.emitNode(m_expr2); + if (fallThroughMeansTrue) + generator.emitJumpIfFalse(temp, falseTarget); + else + generator.emitJumpIfTrue(temp, trueTarget); + } +} + +// ------------------------------ ConditionalNode ------------------------------ + +RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> newDst = generator.finalDestination(dst); + RefPtr<Label> beforeElse = generator.newLabel(); + RefPtr<Label> afterElse = generator.newLabel(); + + if (m_logical->hasConditionContextCodegen()) { + RefPtr<Label> beforeThen = generator.newLabel(); + generator.emitNodeInConditionContext(m_logical, beforeThen.get(), beforeElse.get(), true); + generator.emitLabel(beforeThen.get()); + } else { + RegisterID* cond = generator.emitNode(m_logical); + generator.emitJumpIfFalse(cond, beforeElse.get()); + } + + generator.emitNode(newDst.get(), m_expr1); + generator.emitJump(afterElse.get()); + + generator.emitLabel(beforeElse.get()); + generator.emitNode(newDst.get(), m_expr2); + + generator.emitLabel(afterElse.get()); + + return newDst.get(); +} + +// ------------------------------ ReadModifyResolveNode ----------------------------------- + +// FIXME: should this be moved to be a method on BytecodeGenerator? +static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& generator, RegisterID* dst, RegisterID* src1, ExpressionNode* m_right, Operator oper, OperandTypes types, ReadModifyResolveNode* emitExpressionInfoForMe = 0) +{ + OpcodeID opcodeID; + switch (oper) { + case OpMultEq: + opcodeID = op_mul; + break; + case OpDivEq: + opcodeID = op_div; + break; + case OpPlusEq: + if (m_right->isAdd() && m_right->resultDescriptor().definitelyIsString()) + return static_cast<AddNode*>(m_right)->emitStrcat(generator, dst, src1, emitExpressionInfoForMe); + opcodeID = op_add; + break; + case OpMinusEq: + opcodeID = op_sub; + break; + case OpLShift: + opcodeID = op_lshift; + break; + case OpRShift: + opcodeID = op_rshift; + break; + case OpURShift: + opcodeID = op_urshift; + break; + case OpAndEq: + opcodeID = op_bitand; + break; + case OpXOrEq: + opcodeID = op_bitxor; + break; + case OpOrEq: + opcodeID = op_bitor; + break; + case OpModEq: + opcodeID = op_mod; + break; + default: + ASSERT_NOT_REACHED(); + return dst; + } + + RegisterID* src2 = generator.emitNode(m_right); + + // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. + // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. + if (emitExpressionInfoForMe) + generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); + + return generator.emitBinaryOp(opcodeID, dst, src1, src2, types); +} + +RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) { + return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + } + + if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { + RefPtr<RegisterID> result = generator.newTemporary(); + generator.emitMove(result.get(), local); + emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + generator.emitMove(local, result.get()); + return generator.moveToDestinationIfNeeded(dst, result.get()); + } + + RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + return generator.moveToDestinationIfNeeded(dst, result); + } + + 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* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + generator.emitPutScopedVar(depth, index, result, globalObject); + return result; + } + + RefPtr<RegisterID> src1 = generator.tempDestination(dst); + generator.emitExpressionInfo(divot() - startOffset() + m_ident.size(), m_ident.size(), 0); + RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident); + RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); + return generator.emitPutById(base.get(), m_ident, result); +} + +// ------------------------------ AssignResolveNode ----------------------------------- + +RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (RegisterID* local = generator.registerFor(m_ident)) { + if (generator.isLocalConstant(m_ident)) + return generator.emitNode(dst, m_right); + + RegisterID* result = generator.emitNode(local, m_right); + return generator.moveToDestinationIfNeeded(dst, result); + } + + int index = 0; + size_t depth = 0; + JSObject* globalObject = 0; + if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { + if (dst == generator.ignoredResult()) + dst = 0; + RegisterID* value = generator.emitNode(dst, m_right); + generator.emitPutScopedVar(depth, index, value, globalObject); + return value; + } + + RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); + if (dst == generator.ignoredResult()) + dst = 0; + RegisterID* value = generator.emitNode(dst, m_right); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitPutById(base.get(), m_ident, value); +} + +// ------------------------------ AssignDotNode ----------------------------------- + +RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); + RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); + RegisterID* result = generator.emitNode(value.get(), m_right); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutById(base.get(), m_ident, result); + return generator.moveToDestinationIfNeeded(dst, result); +} + +// ------------------------------ ReadModifyDotNode ----------------------------------- + +RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); + RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + return generator.emitPutById(base.get(), m_ident, updatedValue); +} + +// ------------------------------ AssignErrorNode ----------------------------------- + +RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference."); +} + +// ------------------------------ AssignBracketNode ----------------------------------- + +RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); + RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); + RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); + RegisterID* result = generator.emitNode(value.get(), m_right); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), result); + return generator.moveToDestinationIfNeeded(dst, result); +} + +// ------------------------------ ReadModifyBracketNode ----------------------------------- + +RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); + RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); + + generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); + RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); + RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutByVal(base.get(), property.get(), updatedValue); + + return updatedValue; +} + +// ------------------------------ CommaNode ------------------------------------ + +RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ASSERT(m_expressions.size() > 1); + for (size_t i = 0; i < m_expressions.size() - 1; i++) + generator.emitNode(generator.ignoredResult(), m_expressions[i]); + return generator.emitNode(dst, m_expressions.last()); +} + +// ------------------------------ ConstDeclNode ------------------------------------ + +RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) +{ + if (RegisterID* local = generator.constRegisterFor(m_ident)) { + if (!m_init) + return local; + + return generator.emitNode(local, m_init); + } + + if (generator.codeType() != EvalCode) { + if (m_init) + return generator.emitNode(m_init); + else + return generator.emitResolve(generator.newTemporary(), m_ident); + } + // 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) : generator.emitLoad(0, jsUndefined()); + return generator.emitPutById(base.get(), m_ident, value); +} + +RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + RegisterID* result = 0; + for (ConstDeclNode* n = this; n; n = n->m_next) + result = n->emitCodeSingle(generator); + + return result; +} + +// ------------------------------ ConstStatementNode ----------------------------- + +RegisterID* ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + return generator.emitNode(m_next); +} + +// ------------------------------ SourceElements ------------------------------- + + +inline StatementNode* SourceElements::lastStatement() const +{ + size_t size = m_statements.size(); + return size ? m_statements[size - 1] : 0; +} + +inline void SourceElements::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + size_t size = m_statements.size(); + for (size_t i = 0; i < size; ++i) + generator.emitNode(dst, m_statements[i]); +} + +// ------------------------------ BlockNode ------------------------------------ + +inline StatementNode* BlockNode::lastStatement() const +{ + return m_statements ? m_statements->lastStatement() : 0; +} + +RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (m_statements) + m_statements->emitBytecode(generator, dst); + return 0; +} + +// ------------------------------ EmptyStatementNode --------------------------- + +RegisterID* EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + return dst; +} + +// ------------------------------ DebuggerStatementNode --------------------------- + +RegisterID* DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine()); + return dst; +} + +// ------------------------------ ExprStatementNode ---------------------------- + +RegisterID* ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + ASSERT(m_expr); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + return generator.emitNode(dst, m_expr); +} + +// ------------------------------ VarStatementNode ---------------------------- + +RegisterID* VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + ASSERT(m_expr); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + return generator.emitNode(m_expr); +} + +// ------------------------------ IfNode --------------------------------------- + +RegisterID* IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + RefPtr<Label> afterThen = generator.newLabel(); + + if (m_condition->hasConditionContextCodegen()) { + RefPtr<Label> beforeThen = generator.newLabel(); + generator.emitNodeInConditionContext(m_condition, beforeThen.get(), afterThen.get(), true); + generator.emitLabel(beforeThen.get()); + } else { + RegisterID* cond = generator.emitNode(m_condition); + generator.emitJumpIfFalse(cond, afterThen.get()); + } + + generator.emitNode(dst, m_ifBlock); + generator.emitLabel(afterThen.get()); + + // FIXME: This should return the last statement executed so that it can be returned as a Completion. + return 0; +} + +// ------------------------------ IfElseNode --------------------------------------- + +RegisterID* IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + RefPtr<Label> beforeElse = generator.newLabel(); + RefPtr<Label> afterElse = generator.newLabel(); + + if (m_condition->hasConditionContextCodegen()) { + RefPtr<Label> beforeThen = generator.newLabel(); + generator.emitNodeInConditionContext(m_condition, beforeThen.get(), beforeElse.get(), true); + generator.emitLabel(beforeThen.get()); + } else { + RegisterID* cond = generator.emitNode(m_condition); + generator.emitJumpIfFalse(cond, beforeElse.get()); + } + + generator.emitNode(dst, m_ifBlock); + generator.emitJump(afterElse.get()); + + generator.emitLabel(beforeElse.get()); + + generator.emitNode(dst, m_elseBlock); + + generator.emitLabel(afterElse.get()); + + // FIXME: This should return the last statement executed so that it can be returned as a Completion. + return 0; +} + +// ------------------------------ DoWhileNode ---------------------------------- + +RegisterID* DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + + RefPtr<Label> topOfLoop = generator.newLabel(); + generator.emitLabel(topOfLoop.get()); + + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); + + generator.emitLabel(scope->continueTarget()); + generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); + if (m_expr->hasConditionContextCodegen()) + generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), false); + else { + RegisterID* cond = generator.emitNode(m_expr); + generator.emitJumpIfTrue(cond, topOfLoop.get()); + } + + generator.emitLabel(scope->breakTarget()); + return result.get(); +} + +// ------------------------------ WhileNode ------------------------------------ + +RegisterID* WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + + generator.emitJump(scope->continueTarget()); + + RefPtr<Label> topOfLoop = generator.newLabel(); + generator.emitLabel(topOfLoop.get()); + + generator.emitNode(dst, m_statement); + + generator.emitLabel(scope->continueTarget()); + generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); + + if (m_expr->hasConditionContextCodegen()) + generator.emitNodeInConditionContext(m_expr, topOfLoop.get(), scope->breakTarget(), false); + else { + RegisterID* cond = generator.emitNode(m_expr); + generator.emitJumpIfTrue(cond, topOfLoop.get()); + } + + generator.emitLabel(scope->breakTarget()); + + // FIXME: This should return the last statement executed so that it can be returned as a Completion + return 0; +} + +// ------------------------------ ForNode -------------------------------------- + +RegisterID* ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + if (m_expr1) + generator.emitNode(generator.ignoredResult(), m_expr1); + + RefPtr<Label> condition = generator.newLabel(); + generator.emitJump(condition.get()); + + RefPtr<Label> topOfLoop = generator.newLabel(); + generator.emitLabel(topOfLoop.get()); + + RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); + + generator.emitLabel(scope->continueTarget()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + if (m_expr3) + generator.emitNode(generator.ignoredResult(), m_expr3); + + generator.emitLabel(condition.get()); + if (m_expr2) { + if (m_expr2->hasConditionContextCodegen()) + generator.emitNodeInConditionContext(m_expr2, topOfLoop.get(), scope->breakTarget(), false); + else { + RegisterID* cond = generator.emitNode(m_expr2); + generator.emitJumpIfTrue(cond, topOfLoop.get()); + } + } else + generator.emitJump(topOfLoop.get()); + + generator.emitLabel(scope->breakTarget()); + return result.get(); +} + +// ------------------------------ ForInNode ------------------------------------ + +RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); + + if (!m_lexpr->isLocation()) + return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference."); + + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + if (m_init) + generator.emitNode(generator.ignoredResult(), m_init); + + RefPtr<RegisterID> base = generator.newTemporary(); + generator.emitNode(base.get(), m_expr); + RefPtr<RegisterID> i = generator.newTemporary(); + RefPtr<RegisterID> size = generator.newTemporary(); + RefPtr<RegisterID> expectedSubscript; + RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), base.get(), i.get(), size.get(), scope->breakTarget()); + generator.emitJump(scope->continueTarget()); + + RefPtr<Label> loopStart = generator.newLabel(); + generator.emitLabel(loopStart.get()); + + RegisterID* propertyName; + bool optimizedForinAccess = false; + if (m_lexpr->isResolveNode()) { + const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); + propertyName = generator.registerFor(ident); + if (!propertyName) { + propertyName = generator.newTemporary(); + RefPtr<RegisterID> protect = propertyName; + RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident); + + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitPutById(base, ident, propertyName); + } else { + expectedSubscript = generator.emitMove(generator.newTemporary(), propertyName); + generator.pushOptimisedForIn(expectedSubscript.get(), iter.get(), i.get(), propertyName); + optimizedForinAccess = true; + } + } else if (m_lexpr->isDotAccessorNode()) { + DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); + 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); + 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); + } + + generator.emitNode(dst, m_statement); + + if (optimizedForinAccess) + generator.popOptimisedForIn(); + + generator.emitLabel(scope->continueTarget()); + generator.emitNextPropertyName(propertyName, base.get(), i.get(), size.get(), iter.get(), loopStart.get()); + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + generator.emitLabel(scope->breakTarget()); + return dst; +} + +// ------------------------------ ContinueNode --------------------------------- + +// ECMA 12.7 +RegisterID* ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + 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 +RegisterID* BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + 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 ----------------------------------- + +RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + if (generator.codeType() != FunctionCode) + return emitThrowError(generator, SyntaxError, "Invalid return statement."); + + if (dst == generator.ignoredResult()) + dst = 0; + RegisterID* r0 = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined()); + RefPtr<RegisterID> returnRegister; + if (generator.scopeDepth()) { + RefPtr<Label> l0 = generator.newLabel(); + if (generator.hasFinaliser() && !r0->isTemporary()) { + returnRegister = generator.emitMove(generator.newTemporary(), r0); + r0 = returnRegister.get(); + } + generator.emitJumpScopes(l0.get(), 0); + generator.emitLabel(l0.get()); + } + generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); + return generator.emitReturn(r0); +} + +// ------------------------------ WithNode ------------------------------------- + +RegisterID* WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + RefPtr<RegisterID> scope = generator.newTemporary(); + generator.emitNode(scope.get(), m_expr); // scope must be protected until popped + generator.emitExpressionInfo(m_divot, m_expressionLength, 0); + generator.emitPushScope(scope.get()); + RegisterID* result = generator.emitNode(dst, m_statement); + generator.emitPopScope(); + return result; +} + +// ------------------------------ CaseClauseNode -------------------------------- + +inline void CaseClauseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (m_statements) + m_statements->emitBytecode(generator, dst); +} + +// ------------------------------ CaseBlockNode -------------------------------- + +enum SwitchKind { + SwitchUnset = 0, + SwitchNumber = 1, + SwitchString = 2, + SwitchNeither = 3 +}; + +static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num) +{ + for (; list; list = list->getNext()) { + ExpressionNode* clauseExpression = list->getClause()->expr(); + literalVector.append(clauseExpression); + if (clauseExpression->isNumber()) { + double value = static_cast<NumberNode*>(clauseExpression)->value(); + int32_t intVal = static_cast<int32_t>(value); + if ((typeForTable & ~SwitchNumber) || (intVal != value)) { + typeForTable = SwitchNeither; + break; + } + 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; + } +} + +SwitchInfo::SwitchType CaseBlockNode::tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) +{ + SwitchKind typeForTable = SwitchUnset; + bool singleCharacterSwitch = true; + + processClauseList(m_list1, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); + processClauseList(m_list2, 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; + } + + return SwitchInfo::SwitchString; +} + +RegisterID* CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) +{ + RefPtr<Label> defaultLabel; + Vector<RefPtr<Label>, 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); + + 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; 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; 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()); + } + + RegisterID* result = 0; + + size_t i = 0; + for (ClauseListNode* list = m_list1; list; list = list->getNext()) { + generator.emitLabel(labelVector[i++].get()); + list->getClause()->emitBytecode(generator, dst); + } + + if (m_defaultClause) { + generator.emitLabel(defaultLabel.get()); + m_defaultClause->emitBytecode(generator, dst); + } + + for (ClauseListNode* list = m_list2; list; list = list->getNext()) { + generator.emitLabel(labelVector[i++].get()); + list->getClause()->emitBytecode(generator, dst); + } + if (!m_defaultClause) + generator.emitLabel(defaultLabel.get()); + + 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 ----------------------------------- + +RegisterID* SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch); + + RefPtr<RegisterID> r0 = generator.emitNode(m_expr); + RegisterID* r1 = m_block->emitBytecodeForBlock(generator, r0.get(), dst); + + generator.emitLabel(scope->breakTarget()); + return r1; +} + +// ------------------------------ LabelNode ------------------------------------ + +RegisterID* LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + if (generator.breakTarget(m_name)) + return emitThrowError(generator, SyntaxError, "Duplicate label: %s.", m_name); + + RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); + RegisterID* r0 = generator.emitNode(dst, m_statement); + + generator.emitLabel(scope->breakTarget()); + return r0; +} + +// ------------------------------ ThrowNode ------------------------------------ + +RegisterID* ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + if (dst == generator.ignoredResult()) + dst = 0; + RefPtr<RegisterID> expr = generator.emitNode(m_expr); + generator.emitExpressionInfo(divot(), startOffset(), endOffset()); + generator.emitThrow(expr.get()); + return 0; +} + +// ------------------------------ TryNode -------------------------------------- + +RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + // NOTE: The catch and finally blocks must be labeled explicitly, so the + // optimizer knows they may be jumped to from anywhere. + + generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); + + RefPtr<Label> tryStartLabel = generator.newLabel(); + RefPtr<Label> 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); + + if (m_catchBlock) { + RefPtr<Label> catchEndLabel = generator.newLabel(); + + // Normal path: jump over the catch block. + generator.emitJump(catchEndLabel.get()); + + // Uncaught exception path: the catch block. + RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); + RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get()); + if (m_catchHasEval) { + RefPtr<RegisterID> dynamicScopeObject = generator.emitNewObject(generator.newTemporary()); + generator.emitPutById(dynamicScopeObject.get(), m_exceptionIdent, exceptionRegister.get()); + generator.emitMove(exceptionRegister.get(), dynamicScopeObject.get()); + generator.emitPushScope(exceptionRegister.get()); + } else + generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get()); + generator.emitNode(dst, m_catchBlock); + generator.emitPopScope(); + generator.emitLabel(catchEndLabel.get()); + } + + if (m_finallyBlock) { + 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<Label> finallyEndLabel = generator.newLabel(); + + // Normal path: invoke the finally block, then jump over it. + generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); + generator.emitJump(finallyEndLabel.get()); + + // Uncaught exception path: invoke the finally block, then re-throw the exception. + RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); + RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get()); + generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); + generator.emitThrow(tempExceptionRegister.get()); + + // The finally block. + generator.emitLabel(finallyStart.get()); + generator.emitNode(dst, m_finallyBlock); + generator.emitSubroutineReturn(finallyReturnAddr.get()); + + generator.emitLabel(finallyEndLabel.get()); + } + + return dst; +} + +// ------------------------------ ScopeNode ----------------------------- + +inline void ScopeNode::emitStatementsBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (m_data->m_statements) + m_data->m_statements->emitBytecode(generator, dst); +} + +// ------------------------------ ProgramNode ----------------------------- + +RegisterID* ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); + + RefPtr<RegisterID> dstRegister = generator.newTemporary(); + generator.emitLoad(dstRegister.get(), jsUndefined()); + emitStatementsBytecode(generator, dstRegister.get()); + + generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); + generator.emitEnd(dstRegister.get()); + return 0; +} + +// ------------------------------ EvalNode ----------------------------- + +RegisterID* EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); + + RefPtr<RegisterID> dstRegister = generator.newTemporary(); + generator.emitLoad(dstRegister.get(), jsUndefined()); + emitStatementsBytecode(generator, dstRegister.get()); + + generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); + generator.emitEnd(dstRegister.get()); + return 0; +} + +// ------------------------------ FunctionBodyNode ----------------------------- + +RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) +{ + generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine()); + emitStatementsBytecode(generator, generator.ignoredResult()); + StatementNode* singleStatement = this->singleStatement(); + if (singleStatement && singleStatement->isBlock()) { + StatementNode* lastStatementInBlock = static_cast<BlockNode*>(singleStatement)->lastStatement(); + if (lastStatementInBlock && lastStatementInBlock->isReturnNode()) + return 0; + } + + RegisterID* r0 = generator.emitLoad(0, jsUndefined()); + generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); + generator.emitReturn(r0); + return 0; +} + +// ------------------------------ FuncDeclNode --------------------------------- + +RegisterID* FuncDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + if (dst == generator.ignoredResult()) + dst = 0; + return dst; +} + +// ------------------------------ FuncExprNode --------------------------------- + +RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +{ + return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); +} + +} // namespace JSC diff --git a/JavaScriptCore/config.h b/JavaScriptCore/config.h index 6681761..30757db 100644 --- a/JavaScriptCore/config.h +++ b/JavaScriptCore/config.h @@ -57,7 +57,6 @@ /* FIXME: if all platforms have these, do they really need #defines? */ #define HAVE_STDINT_H 1 -#define HAVE_STRING_H 1 #define WTF_CHANGES 1 @@ -74,3 +73,15 @@ #include <wtf/DisallowCType.h> #endif +#if PLATFORM(CHROMIUM) +#if !defined(WTF_USE_V8) +#define WTF_USE_V8 1 +#endif +#endif /* PLATFORM(CHROMIUM) */ + +#if !defined(WTF_USE_V8) +#define WTF_USE_V8 0 +#endif /* !defined(WTF_USE_V8) */ + +/* Using V8 implies not using JSC and vice versa */ +#define WTF_USE_JSC !WTF_USE_V8 diff --git a/JavaScriptCore/debugger/Debugger.cpp b/JavaScriptCore/debugger/Debugger.cpp index 7d791e7..902a802 100644 --- a/JavaScriptCore/debugger/Debugger.cpp +++ b/JavaScriptCore/debugger/Debugger.cpp @@ -22,16 +22,16 @@ #include "config.h" #include "Debugger.h" -#include "JSGlobalObject.h" +#include "CollectorHeapIterator.h" +#include "Error.h" #include "Interpreter.h" +#include "JSFunction.h" +#include "JSGlobalObject.h" #include "Parser.h" +#include "Protect.h" namespace JSC { -Debugger::Debugger() -{ -} - Debugger::~Debugger() { HashSet<JSGlobalObject*>::iterator end = m_globalObjects.end(); @@ -53,18 +53,59 @@ void Debugger::detach(JSGlobalObject* globalObject) globalObject->setDebugger(0); } +void Debugger::recompileAllJSFunctions(JSGlobalData* globalData) +{ + // If JavaScript is running, it's not safe to recompile, since we'll end + // up throwing away code that is live on the stack. + ASSERT(!globalData->dynamicGlobalObject); + if (globalData->dynamicGlobalObject) + return; + + typedef HashSet<FunctionExecutable*> FunctionExecutableSet; + typedef HashMap<SourceProvider*, ExecState*> SourceProviderMap; + + FunctionExecutableSet functionExecutables; + SourceProviderMap sourceProviders; + + Heap::iterator heapEnd = globalData->heap.primaryHeapEnd(); + for (Heap::iterator it = globalData->heap.primaryHeapBegin(); it != heapEnd; ++it) { + if (!(*it)->inherits(&JSFunction::info)) + continue; + + JSFunction* function = asFunction(*it); + if (function->executable()->isHostFunction()) + continue; + + FunctionExecutable* executable = function->jsExecutable(); + + // Check if the function is already in the set - if so, + // we've already retranslated it, nothing to do here. + if (!functionExecutables.add(executable).second) + continue; + + ExecState* exec = function->scope().globalObject()->JSGlobalObject::globalExec(); + executable->recompile(exec); + if (function->scope().globalObject()->debugger() == this) + sourceProviders.add(executable->source().provider(), exec); + } + + // Call sourceParsed() after reparsing all functions because it will execute + // JavaScript in the inspector. + SourceProviderMap::const_iterator end = sourceProviders.end(); + for (SourceProviderMap::const_iterator iter = sourceProviders.begin(); iter != end; ++iter) + sourceParsed(iter->second, SourceCode(iter->first), -1, 0); +} + JSValue evaluateInGlobalCallFrame(const UString& script, JSValue& exception, JSGlobalObject* globalObject) { CallFrame* globalCallFrame = globalObject->globalExec(); - int errLine; - UString errMsg; - SourceCode source = makeSource(script); - RefPtr<EvalNode> evalNode = globalObject->globalData()->parser->parse<EvalNode>(globalCallFrame, globalObject->debugger(), source, &errLine, &errMsg); - if (!evalNode) - return Error::create(globalCallFrame, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url()); + RefPtr<EvalExecutable> eval = EvalExecutable::create(globalCallFrame, makeSource(script)); + JSObject* error = eval->compile(globalCallFrame, globalCallFrame->scopeChain()); + if (error) + return error; - return globalObject->globalData()->interpreter->execute(evalNode.get(), globalCallFrame, globalObject, globalCallFrame->scopeChain(), &exception); + return globalObject->globalData()->interpreter->execute(eval.get(), globalCallFrame, globalObject, globalCallFrame->scopeChain(), &exception); } } // namespace JSC diff --git a/JavaScriptCore/debugger/Debugger.h b/JavaScriptCore/debugger/Debugger.h index 98d0935..3ee9767 100644 --- a/JavaScriptCore/debugger/Debugger.h +++ b/JavaScriptCore/debugger/Debugger.h @@ -1,7 +1,7 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) * Copyright (C) 2001 Peter Kelly (pmk@post.com) - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -22,40 +22,42 @@ #ifndef Debugger_h #define Debugger_h -#include "Protect.h" +#include <wtf/HashSet.h> namespace JSC { class DebuggerCallFrame; class ExecState; + class JSGlobalData; class JSGlobalObject; + class JSValue; class SourceCode; class UString; class Debugger { public: - Debugger(); virtual ~Debugger(); void attach(JSGlobalObject*); virtual void detach(JSGlobalObject*); - virtual void sourceParsed(ExecState*, const SourceCode&, int errorLine, const UString& errorMsg) = 0; - virtual void exception(const DebuggerCallFrame&, intptr_t sourceID, int lineno) = 0; - virtual void atStatement(const DebuggerCallFrame&, intptr_t sourceID, int lineno) = 0; - virtual void callEvent(const DebuggerCallFrame&, intptr_t sourceID, int lineno) = 0; - virtual void returnEvent(const DebuggerCallFrame&, intptr_t sourceID, int lineno) = 0; + virtual void sourceParsed(ExecState*, const SourceCode&, int errorLineNumber, const UString& errorMessage) = 0; + virtual void exception(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; + virtual void atStatement(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; + virtual void callEvent(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; + virtual void returnEvent(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; - virtual void willExecuteProgram(const DebuggerCallFrame&, intptr_t sourceID, int lineno) = 0; - virtual void didExecuteProgram(const DebuggerCallFrame&, intptr_t sourceID, int lineno) = 0; - virtual void didReachBreakpoint(const DebuggerCallFrame&, intptr_t sourceID, int lineno) = 0; + virtual void willExecuteProgram(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; + virtual void didExecuteProgram(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; + virtual void didReachBreakpoint(const DebuggerCallFrame&, intptr_t sourceID, int lineNumber) = 0; + + void recompileAllJSFunctions(JSGlobalData*); private: HashSet<JSGlobalObject*> m_globalObjects; }; - // This method exists only for backwards compatibility with existing - // WebScriptDebugger clients + // This function exists only for backwards compatibility with existing WebScriptDebugger clients. JSValue evaluateInGlobalCallFrame(const UString&, JSValue& exception, JSGlobalObject*); } // namespace JSC diff --git a/JavaScriptCore/debugger/DebuggerActivation.cpp b/JavaScriptCore/debugger/DebuggerActivation.cpp index 34d0447..d47db5b 100644 --- a/JavaScriptCore/debugger/DebuggerActivation.cpp +++ b/JavaScriptCore/debugger/DebuggerActivation.cpp @@ -71,24 +71,24 @@ bool DebuggerActivation::deleteProperty(ExecState* exec, const Identifier& prope return m_activation->deleteProperty(exec, propertyName); } -void DebuggerActivation::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void DebuggerActivation::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { m_activation->getPropertyNames(exec, propertyNames); } -bool DebuggerActivation::getPropertyAttributes(JSC::ExecState* exec, const Identifier& propertyName, unsigned& attributes) const +bool DebuggerActivation::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { - return m_activation->getPropertyAttributes(exec, propertyName, attributes); + return m_activation->getOwnPropertyDescriptor(exec, propertyName, descriptor); } -void DebuggerActivation::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction) +void DebuggerActivation::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) { - m_activation->defineGetter(exec, propertyName, getterFunction); + m_activation->defineGetter(exec, propertyName, getterFunction, attributes); } -void DebuggerActivation::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction) +void DebuggerActivation::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes) { - m_activation->defineSetter(exec, propertyName, setterFunction); + m_activation->defineSetter(exec, propertyName, setterFunction, attributes); } JSValue DebuggerActivation::lookupGetter(ExecState* exec, const Identifier& propertyName) diff --git a/JavaScriptCore/debugger/DebuggerActivation.h b/JavaScriptCore/debugger/DebuggerActivation.h index 82cde4d..373e62d 100644 --- a/JavaScriptCore/debugger/DebuggerActivation.h +++ b/JavaScriptCore/debugger/DebuggerActivation.h @@ -42,18 +42,21 @@ namespace JSC { virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue, unsigned attributes); virtual bool deleteProperty(ExecState*, const Identifier& propertyName); - virtual void getPropertyNames(ExecState*, PropertyNameArray&); - virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; - virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction); - virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); + virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes); + virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes); virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName); virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName); static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | JSObject::StructureFlags; + private: JSActivation* m_activation; }; diff --git a/JavaScriptCore/debugger/DebuggerCallFrame.cpp b/JavaScriptCore/debugger/DebuggerCallFrame.cpp index cd8702b..c6b4223 100644 --- a/JavaScriptCore/debugger/DebuggerCallFrame.cpp +++ b/JavaScriptCore/debugger/DebuggerCallFrame.cpp @@ -41,10 +41,10 @@ const UString* DebuggerCallFrame::functionName() const if (!m_callFrame->codeBlock()) return 0; - JSFunction* function = static_cast<JSFunction*>(m_callFrame->callee()); + JSFunction* function = asFunction(m_callFrame->callee()); if (!function) return 0; - return &function->name(&m_callFrame->globalData()); + return &function->name(m_callFrame); } UString DebuggerCallFrame::calculatedFunctionName() const @@ -52,10 +52,10 @@ UString DebuggerCallFrame::calculatedFunctionName() const if (!m_callFrame->codeBlock()) return 0; - JSFunction* function = static_cast<JSFunction*>(m_callFrame->callee()); + JSFunction* function = asFunction(m_callFrame->callee()); if (!function) return 0; - return function->calculatedDisplayName(&m_callFrame->globalData()); + return function->calculatedDisplayName(m_callFrame); } DebuggerCallFrame::Type DebuggerCallFrame::type() const @@ -79,14 +79,12 @@ JSValue DebuggerCallFrame::evaluate(const UString& script, JSValue& exception) c if (!m_callFrame->codeBlock()) return JSValue(); - int errLine; - UString errMsg; - SourceCode source = makeSource(script); - RefPtr<EvalNode> evalNode = m_callFrame->scopeChain()->globalData->parser->parse<EvalNode>(m_callFrame, m_callFrame->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); - if (!evalNode) - return Error::create(m_callFrame, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url()); + RefPtr<EvalExecutable> eval = EvalExecutable::create(m_callFrame, makeSource(script)); + JSObject* error = eval->compile(m_callFrame, m_callFrame->scopeChain()); + if (error) + return error; - return m_callFrame->scopeChain()->globalData->interpreter->execute(evalNode.get(), m_callFrame, thisObject(), m_callFrame->scopeChain(), &exception); + return m_callFrame->scopeChain()->globalData->interpreter->execute(eval.get(), m_callFrame, thisObject(), m_callFrame->scopeChain(), &exception); } } // namespace JSC diff --git a/JavaScriptCore/interpreter/CachedCall.h b/JavaScriptCore/interpreter/CachedCall.h index 767c262..eb48a03 100644 --- a/JavaScriptCore/interpreter/CachedCall.h +++ b/JavaScriptCore/interpreter/CachedCall.h @@ -38,9 +38,10 @@ namespace JSC { : m_valid(false) , m_interpreter(callFrame->interpreter()) , m_exception(exception) - , m_globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : function->scope().node()->globalObject()) + , m_globalObjectScope(callFrame, function->scope().globalObject()) { - m_closure = m_interpreter->prepareForRepeatCall(function->body(), callFrame, function, argCount, function->scope().node(), exception); + ASSERT(!function->isHostFunction()); + m_closure = m_interpreter->prepareForRepeatCall(function->jsExecutable(), callFrame, function, argCount, function->scope().node(), exception); m_valid = !*exception; } @@ -51,7 +52,14 @@ namespace JSC { } void setThis(JSValue v) { m_closure.setArgument(0, v); } void setArgument(int n, JSValue v) { m_closure.setArgument(n + 1, v); } - CallFrame* newCallFrame() { return m_closure.newCallFrame; } + + CallFrame* newCallFrame(ExecState* exec) + { + CallFrame* callFrame = m_closure.newCallFrame; + callFrame->setScopeChain(exec->scopeChain()); + return callFrame; + } + ~CachedCall() { if (m_valid) diff --git a/JavaScriptCore/interpreter/CallFrame.h b/JavaScriptCore/interpreter/CallFrame.h index 92ec06e..fff4c9b 100644 --- a/JavaScriptCore/interpreter/CallFrame.h +++ b/JavaScriptCore/interpreter/CallFrame.h @@ -39,7 +39,11 @@ namespace JSC { public: JSFunction* callee() const { return this[RegisterFile::Callee].function(); } CodeBlock* codeBlock() const { return this[RegisterFile::CodeBlock].Register::codeBlock(); } - ScopeChainNode* scopeChain() const { return this[RegisterFile::ScopeChain].Register::scopeChain(); } + ScopeChainNode* scopeChain() const + { + ASSERT(this[RegisterFile::ScopeChain].Register::scopeChain()); + return this[RegisterFile::ScopeChain].Register::scopeChain(); + } int argumentCount() const { return this[RegisterFile::ArgumentCount].i(); } JSValue thisValue(); @@ -51,14 +55,14 @@ namespace JSC { // Differs from dynamicGlobalObject() during function calls across web browser frames. JSGlobalObject* lexicalGlobalObject() const { - return scopeChain()->globalObject(); + return scopeChain()->globalObject; } // Differs from lexicalGlobalObject because this will have DOM window shell rather than // the actual DOM window, which can't be "this" for security reasons. JSObject* globalThisValue() const { - return scopeChain()->globalThisObject(); + return scopeChain()->globalThis; } // FIXME: Elsewhere, we use JSGlobalData* rather than JSGlobalData&. @@ -66,6 +70,7 @@ namespace JSC { // or a pointer everywhere. JSGlobalData& globalData() const { + ASSERT(scopeChain()->globalData); return *scopeChain()->globalData; } diff --git a/JavaScriptCore/interpreter/CallFrameClosure.h b/JavaScriptCore/interpreter/CallFrameClosure.h index 9085327..a301060 100644 --- a/JavaScriptCore/interpreter/CallFrameClosure.h +++ b/JavaScriptCore/interpreter/CallFrameClosure.h @@ -32,7 +32,7 @@ struct CallFrameClosure { CallFrame* oldCallFrame; CallFrame* newCallFrame; JSFunction* function; - FunctionBodyNode* functionBody; + FunctionExecutable* functionExecutable; JSGlobalData* globalData; Register* oldEnd; ScopeChainNode* scopeChain; diff --git a/JavaScriptCore/interpreter/Interpreter.cpp b/JavaScriptCore/interpreter/Interpreter.cpp index f102739..ed8bf5b 100644 --- a/JavaScriptCore/interpreter/Interpreter.cpp +++ b/JavaScriptCore/interpreter/Interpreter.cpp @@ -91,8 +91,8 @@ static int depth(CodeBlock* codeBlock, ScopeChain& sc) #if USE(INTERPRETER) NEVER_INLINE bool Interpreter::resolve(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) { - int dst = (vPC + 1)->u.operand; - int property = (vPC + 2)->u.operand; + int dst = vPC[1].u.operand; + int property = vPC[2].u.operand; ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); @@ -121,9 +121,9 @@ NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vP { CodeBlock* codeBlock = callFrame->codeBlock(); - int dst = (vPC + 1)->u.operand; - int property = (vPC + 2)->u.operand; - int skip = (vPC + 3)->u.operand + codeBlock->needsFullScopeChain(); + int dst = vPC[1].u.operand; + int property = vPC[2].u.operand; + int skip = vPC[3].u.operand + codeBlock->needsFullScopeChain(); ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); @@ -152,12 +152,12 @@ NEVER_INLINE bool Interpreter::resolveSkip(CallFrame* callFrame, Instruction* vP NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) { - int dst = (vPC + 1)->u.operand; - JSGlobalObject* globalObject = static_cast<JSGlobalObject*>((vPC + 2)->u.jsCell); + int dst = vPC[1].u.operand; + JSGlobalObject* globalObject = static_cast<JSGlobalObject*>(vPC[2].u.jsCell); ASSERT(globalObject->isGlobalObject()); - int property = (vPC + 3)->u.operand; - Structure* structure = (vPC + 4)->u.structure; - int offset = (vPC + 5)->u.operand; + int property = vPC[3].u.operand; + Structure* structure = vPC[4].u.structure; + int offset = vPC[5].u.operand; if (structure == globalObject->structure()) { callFrame->r(dst) = JSValue(globalObject->getDirectOffset(offset)); @@ -169,7 +169,7 @@ NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* PropertySlot slot(globalObject); if (globalObject->getPropertySlot(callFrame, ident, slot)) { JSValue result = slot.getValue(callFrame, ident); - if (slot.isCacheable() && !globalObject->structure()->isDictionary() && slot.slotBase() == globalObject) { + if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { if (vPC[4].u.structure) vPC[4].u.structure->deref(); globalObject->structure()->ref(); @@ -192,16 +192,16 @@ NEVER_INLINE bool Interpreter::resolveGlobal(CallFrame* callFrame, Instruction* NEVER_INLINE void Interpreter::resolveBase(CallFrame* callFrame, Instruction* vPC) { - int dst = (vPC + 1)->u.operand; - int property = (vPC + 2)->u.operand; + int dst = vPC[1].u.operand; + int property = vPC[2].u.operand; callFrame->r(dst) = JSValue(JSC::resolveBase(callFrame, callFrame->codeBlock()->identifier(property), callFrame->scopeChain())); } NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) { - int baseDst = (vPC + 1)->u.operand; - int propDst = (vPC + 2)->u.operand; - int property = (vPC + 3)->u.operand; + int baseDst = vPC[1].u.operand; + int propDst = vPC[2].u.operand; + int property = vPC[3].u.operand; ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); @@ -233,51 +233,6 @@ NEVER_INLINE bool Interpreter::resolveBaseAndProperty(CallFrame* callFrame, Inst return false; } -NEVER_INLINE bool Interpreter::resolveBaseAndFunc(CallFrame* callFrame, Instruction* vPC, JSValue& exceptionValue) -{ - int baseDst = (vPC + 1)->u.operand; - int funcDst = (vPC + 2)->u.operand; - int property = (vPC + 3)->u.operand; - - ScopeChainNode* scopeChain = callFrame->scopeChain(); - ScopeChainIterator iter = scopeChain->begin(); - ScopeChainIterator end = scopeChain->end(); - - // FIXME: add scopeDepthIsZero optimization - - ASSERT(iter != end); - - CodeBlock* codeBlock = callFrame->codeBlock(); - Identifier& ident = codeBlock->identifier(property); - JSObject* base; - do { - base = *iter; - PropertySlot slot(base); - if (base->getPropertySlot(callFrame, ident, slot)) { - // ECMA 11.2.3 says that if we hit an activation 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. - // We also handle wrapper substitution for the global object at the same time. - JSObject* thisObj = base->toThisObject(callFrame); - JSValue result = slot.getValue(callFrame, ident); - exceptionValue = callFrame->globalData().exception; - if (exceptionValue) - return false; - - callFrame->r(baseDst) = JSValue(thisObj); - callFrame->r(funcDst) = JSValue(result); - return true; - } - ++iter; - } while (iter != end); - - exceptionValue = createUndefinedVariableError(callFrame, ident, vPC - codeBlock->instructions().begin(), codeBlock); - return false; -} - #endif // USE(INTERPRETER) ALWAYS_INLINE CallFrame* Interpreter::slideRegisterWindowForCall(CodeBlock* newCodeBlock, RegisterFile* registerFile, CallFrame* callFrame, size_t registerOffset, int argc) @@ -345,29 +300,31 @@ NEVER_INLINE JSValue Interpreter::callEval(CallFrame* callFrame, RegisterFile* r if (!program.isString()) return program; - UString programSource = asString(program)->value(); + UString programSource = asString(program)->value(callFrame); LiteralParser preparser(callFrame, programSource, LiteralParser::NonStrictJSON); if (JSValue parsedObject = preparser.tryLiteralParse()) return parsedObject; - - + ScopeChainNode* scopeChain = callFrame->scopeChain(); CodeBlock* codeBlock = callFrame->codeBlock(); - RefPtr<EvalNode> evalNode = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue); + RefPtr<EvalExecutable> eval = codeBlock->evalCodeCache().get(callFrame, programSource, scopeChain, exceptionValue); JSValue result = jsUndefined(); - if (evalNode) - result = callFrame->globalData().interpreter->execute(evalNode.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue); + if (eval) + result = callFrame->globalData().interpreter->execute(eval.get(), callFrame, callFrame->thisValue().toThisObject(callFrame), callFrame->registers() - registerFile->start() + registerOffset, scopeChain, &exceptionValue); return result; } Interpreter::Interpreter() - : m_sampler(0) + : m_sampleEntryDepth(0) , m_reentryDepth(0) { privateExecute(InitializeAndReturn, 0, 0, 0); +#if ENABLE(OPCODE_SAMPLING) + enableSampler(); +#endif } #ifndef NDEBUG @@ -386,7 +343,7 @@ void Interpreter::dumpRegisters(CallFrame* callFrame) printf("-----------------------------------------------------------------------------\n"); CodeBlock* codeBlock = callFrame->codeBlock(); - RegisterFile* registerFile = &callFrame->scopeChain()->globalObject()->globalData()->interpreter->registerFile(); + RegisterFile* registerFile = &callFrame->scopeChain()->globalObject->globalData()->interpreter->registerFile(); const Register* it; const Register* end; JSValue v; @@ -490,21 +447,21 @@ NEVER_INLINE bool Interpreter::unwindCallFrame(CallFrame*& callFrame, JSValue ex if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); if (callFrame->callee()) - debugger->returnEvent(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine()); + debugger->returnEvent(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine()); else - debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->lastLine()); + debugger->didExecuteProgram(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->lastLine()); } if (Profiler* profiler = *Profiler::enabledProfilerReference()) { if (callFrame->callee()) profiler->didExecute(callFrame, callFrame->callee()); else - profiler->didExecute(callFrame, codeBlock->ownerNode()->sourceURL(), codeBlock->ownerNode()->lineNo()); + profiler->didExecute(callFrame, codeBlock->ownerExecutable()->sourceURL(), codeBlock->ownerExecutable()->lineNo()); } // If this call frame created an activation or an 'arguments' object, tear it off. if (oldCodeBlock->codeType() == FunctionCode && oldCodeBlock->needsFullScopeChain()) { - while (!scopeChain->object->isObject(&JSActivation::info)) + while (!scopeChain->object->inherits(&JSActivation::info)) scopeChain = scopeChain->pop(); static_cast<JSActivation*>(scopeChain->object)->copyRegisters(callFrame->optionalCalleeArguments()); } else if (Arguments* arguments = callFrame->optionalCalleeArguments()) { @@ -555,8 +512,8 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV exception->putWithAttributes(callFrame, Identifier(callFrame, expressionEndOffsetPropertyName), jsNumber(callFrame, divotPoint + endOffset), ReadOnly | DontDelete); } else exception->putWithAttributes(callFrame, Identifier(callFrame, "line"), jsNumber(callFrame, codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)), ReadOnly | DontDelete); - exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerNode()->sourceID()), ReadOnly | DontDelete); - exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerNode()->sourceURL()), ReadOnly | DontDelete); + exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceId"), jsNumber(callFrame, codeBlock->ownerExecutable()->sourceID()), ReadOnly | DontDelete); + exception->putWithAttributes(callFrame, Identifier(callFrame, "sourceURL"), jsOwnedString(callFrame, codeBlock->ownerExecutable()->sourceURL()), ReadOnly | DontDelete); } if (exception->isWatchdogException()) { @@ -570,7 +527,7 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV if (Debugger* debugger = callFrame->dynamicGlobalObject()->debugger()) { DebuggerCallFrame debuggerCallFrame(callFrame, exceptionValue); - debugger->exception(debuggerCallFrame, codeBlock->ownerNode()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)); + debugger->exception(debuggerCallFrame, codeBlock->ownerExecutable()->sourceID(), codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset)); } // If we throw in the middle of a call instruction, we need to notify @@ -580,7 +537,7 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV #if !ENABLE(JIT) if (isCallBytecode(codeBlock->instructions()[bytecodeOffset].u.opcode)) profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 2].u.operand).jsValue()); - else if (codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct)) + else if (codeBlock->instructions().size() > (bytecodeOffset + 8) && codeBlock->instructions()[bytecodeOffset + 8].u.opcode == getOpcode(op_construct)) profiler->didExecute(callFrame, callFrame->r(codeBlock->instructions()[bytecodeOffset + 10].u.operand).jsValue()); #else int functionRegisterIndex; @@ -610,7 +567,7 @@ NEVER_INLINE HandlerInfo* Interpreter::throwException(CallFrame*& callFrame, JSV return handler; } -JSValue Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception) +JSValue Interpreter::execute(ProgramExecutable* program, CallFrame* callFrame, ScopeChainNode* scopeChain, JSObject* thisObj, JSValue* exception) { ASSERT(!scopeChain->globalData->exception); @@ -621,7 +578,7 @@ JSValue Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, Sco } } - CodeBlock* codeBlock = &programNode->bytecode(scopeChain); + CodeBlock* codeBlock = &program->bytecode(callFrame, scopeChain); Register* oldEnd = m_registerFile.end(); Register* newEnd = oldEnd + codeBlock->m_numParameters + RegisterFile::CallFrameHeaderSize + codeBlock->m_numCalleeRegisters; @@ -630,7 +587,7 @@ JSValue Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, Sco return jsNull(); } - DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject()); + DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject); JSGlobalObject* lastGlobalObject = m_registerFile.globalObject(); JSGlobalObject* globalObject = callFrame->dynamicGlobalObject(); @@ -645,15 +602,15 @@ JSValue Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, Sco Profiler** profiler = Profiler::enabledProfilerReference(); if (*profiler) - (*profiler)->willExecute(newCallFrame, programNode->sourceURL(), programNode->lineNo()); + (*profiler)->willExecute(newCallFrame, program->sourceURL(), program->lineNo()); JSValue result; { - SamplingTool::CallRecord callRecord(m_sampler); + SamplingTool::CallRecord callRecord(m_sampler.get()); m_reentryDepth++; #if ENABLE(JIT) - result = programNode->jitCode(scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); + result = program->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); #else result = privateExecute(Normal, &m_registerFile, newCallFrame, exception); #endif @@ -661,7 +618,7 @@ JSValue Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, Sco } if (*profiler) - (*profiler)->didExecute(callFrame, programNode->sourceURL(), programNode->lineNo()); + (*profiler)->didExecute(callFrame, program->sourceURL(), program->lineNo()); if (m_reentryDepth && lastGlobalObject && globalObject != lastGlobalObject) lastGlobalObject->copyGlobalsTo(m_registerFile); @@ -671,7 +628,7 @@ JSValue Interpreter::execute(ProgramNode* programNode, CallFrame* callFrame, Sco return result; } -JSValue Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception) +JSValue Interpreter::execute(FunctionExecutable* functionExecutable, CallFrame* callFrame, JSFunction* function, JSObject* thisObj, const ArgList& args, ScopeChainNode* scopeChain, JSValue* exception) { ASSERT(!scopeChain->globalData->exception); @@ -690,7 +647,7 @@ JSValue Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* call return jsNull(); } - DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject()); + DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject); CallFrame* newCallFrame = CallFrame::create(oldEnd); size_t dst = 0; @@ -699,7 +656,7 @@ JSValue Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* call for (ArgList::const_iterator it = args.begin(); it != end; ++it) newCallFrame->r(++dst) = *it; - CodeBlock* codeBlock = &functionBodyNode->bytecode(scopeChain); + CodeBlock* codeBlock = &functionExecutable->bytecode(callFrame, scopeChain); newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc); if (UNLIKELY(!newCallFrame)) { *exception = createStackOverflowError(callFrame); @@ -715,11 +672,11 @@ JSValue Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* call JSValue result; { - SamplingTool::CallRecord callRecord(m_sampler); + SamplingTool::CallRecord callRecord(m_sampler.get()); m_reentryDepth++; #if ENABLE(JIT) - result = functionBodyNode->jitCode(scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); + result = functionExecutable->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); #else result = privateExecute(Normal, &m_registerFile, newCallFrame, exception); #endif @@ -733,7 +690,7 @@ JSValue Interpreter::execute(FunctionBodyNode* functionBodyNode, CallFrame* call return result; } -CallFrameClosure Interpreter::prepareForRepeatCall(FunctionBodyNode* functionBodyNode, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain, JSValue* exception) +CallFrameClosure Interpreter::prepareForRepeatCall(FunctionExecutable* FunctionExecutable, CallFrame* callFrame, JSFunction* function, int argCount, ScopeChainNode* scopeChain, JSValue* exception) { ASSERT(!scopeChain->globalData->exception); @@ -757,7 +714,7 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionBodyNode* functionBod for (int i = 0; i < argc; ++i) newCallFrame->r(++dst) = jsUndefined(); - CodeBlock* codeBlock = &functionBodyNode->bytecode(scopeChain); + CodeBlock* codeBlock = &FunctionExecutable->bytecode(callFrame, scopeChain); newCallFrame = slideRegisterWindowForCall(codeBlock, &m_registerFile, newCallFrame, argc + RegisterFile::CallFrameHeaderSize, argc); if (UNLIKELY(!newCallFrame)) { *exception = createStackOverflowError(callFrame); @@ -767,10 +724,10 @@ CallFrameClosure Interpreter::prepareForRepeatCall(FunctionBodyNode* functionBod // a 0 codeBlock indicates a built-in caller newCallFrame->init(codeBlock, 0, scopeChain, callFrame->addHostCallFrameFlag(), 0, argc, function); #if ENABLE(JIT) - functionBodyNode->jitCode(scopeChain); + FunctionExecutable->jitCode(newCallFrame, scopeChain); #endif - CallFrameClosure result = { callFrame, newCallFrame, function, functionBodyNode, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc }; + CallFrameClosure result = { callFrame, newCallFrame, function, FunctionExecutable, scopeChain->globalData, oldEnd, scopeChain, codeBlock->m_numParameters, argc }; return result; } @@ -783,11 +740,11 @@ JSValue Interpreter::execute(CallFrameClosure& closure, JSValue* exception) JSValue result; { - SamplingTool::CallRecord callRecord(m_sampler); + SamplingTool::CallRecord callRecord(m_sampler.get()); m_reentryDepth++; #if ENABLE(JIT) - result = closure.functionBody->generatedJITCode().execute(&m_registerFile, closure.newCallFrame, closure.globalData, exception); + result = closure.functionExecutable->generatedJITCode().execute(&m_registerFile, closure.newCallFrame, closure.globalData, exception); #else result = privateExecute(Normal, &m_registerFile, closure.newCallFrame, exception); #endif @@ -804,12 +761,12 @@ void Interpreter::endRepeatCall(CallFrameClosure& closure) m_registerFile.shrink(closure.oldEnd); } -JSValue Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception) +JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception) { - return execute(evalNode, callFrame, thisObj, m_registerFile.size() + evalNode->bytecode(scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception); + return execute(eval, callFrame, thisObj, m_registerFile.size() + eval->bytecode(callFrame, scopeChain).m_numParameters + RegisterFile::CallFrameHeaderSize, scopeChain, exception); } -JSValue Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue* exception) +JSValue Interpreter::execute(EvalExecutable* eval, CallFrame* callFrame, JSObject* thisObj, int globalRegisterOffset, ScopeChainNode* scopeChain, JSValue* exception) { ASSERT(!scopeChain->globalData->exception); @@ -820,9 +777,9 @@ JSValue Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* } } - DynamicGlobalObjectScope globalObjectScope(callFrame, callFrame->globalData().dynamicGlobalObject ? callFrame->globalData().dynamicGlobalObject : scopeChain->globalObject()); + DynamicGlobalObjectScope globalObjectScope(callFrame, scopeChain->globalObject); - EvalCodeBlock* codeBlock = &evalNode->bytecode(scopeChain); + EvalCodeBlock* codeBlock = &eval->bytecode(callFrame, scopeChain); JSVariableObject* variableObject; for (ScopeChainNode* node = scopeChain; ; node = node->next) { @@ -837,21 +794,20 @@ JSValue Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* BatchedTransitionOptimizer optimizer(variableObject); - const DeclarationStacks::VarStack& varStack = codeBlock->ownerNode()->varStack(); - DeclarationStacks::VarStack::const_iterator varStackEnd = varStack.end(); - for (DeclarationStacks::VarStack::const_iterator it = varStack.begin(); it != varStackEnd; ++it) { - const Identifier& ident = (*it).first; + unsigned numVariables = codeBlock->numVariables(); + for (unsigned i = 0; i < numVariables; ++i) { + const Identifier& ident = codeBlock->variable(i); if (!variableObject->hasProperty(callFrame, ident)) { PutPropertySlot slot; variableObject->put(callFrame, ident, jsUndefined(), slot); } } - const DeclarationStacks::FunctionStack& functionStack = codeBlock->ownerNode()->functionStack(); - DeclarationStacks::FunctionStack::const_iterator functionStackEnd = functionStack.end(); - for (DeclarationStacks::FunctionStack::const_iterator it = functionStack.begin(); it != functionStackEnd; ++it) { + int numFunctions = codeBlock->numberOfFunctionDecls(); + for (int i = 0; i < numFunctions; ++i) { + FunctionExecutable* function = codeBlock->functionDecl(i); PutPropertySlot slot; - variableObject->put(callFrame, (*it)->m_ident, (*it)->makeFunction(callFrame, scopeChain), slot); + variableObject->put(callFrame, function->name(), function->make(callFrame, scopeChain), slot); } } @@ -874,15 +830,15 @@ JSValue Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* Profiler** profiler = Profiler::enabledProfilerReference(); if (*profiler) - (*profiler)->willExecute(newCallFrame, evalNode->sourceURL(), evalNode->lineNo()); + (*profiler)->willExecute(newCallFrame, eval->sourceURL(), eval->lineNo()); JSValue result; { - SamplingTool::CallRecord callRecord(m_sampler); + SamplingTool::CallRecord callRecord(m_sampler.get()); m_reentryDepth++; #if ENABLE(JIT) - result = evalNode->jitCode(scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); + result = eval->jitCode(newCallFrame, scopeChain).execute(&m_registerFile, newCallFrame, scopeChain->globalData, exception); #else result = privateExecute(Normal, &m_registerFile, newCallFrame, exception); #endif @@ -890,7 +846,7 @@ JSValue Interpreter::execute(EvalNode* evalNode, CallFrame* callFrame, JSObject* } if (*profiler) - (*profiler)->didExecute(callFrame, evalNode->sourceURL(), evalNode->lineNo()); + (*profiler)->didExecute(callFrame, eval->sourceURL(), eval->lineNo()); m_registerFile.shrink(oldEnd); return result; @@ -904,22 +860,22 @@ NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHook switch (debugHookID) { case DidEnterCallFrame: - debugger->callEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine); + debugger->callEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine); return; case WillLeaveCallFrame: - debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine); + debugger->returnEvent(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine); return; case WillExecuteStatement: - debugger->atStatement(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine); + debugger->atStatement(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine); return; case WillExecuteProgram: - debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), firstLine); + debugger->willExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), firstLine); return; case DidExecuteProgram: - debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine); + debugger->didExecuteProgram(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine); return; case DidReachBreakpoint: - debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerNode()->sourceID(), lastLine); + debugger->didReachBreakpoint(callFrame, callFrame->codeBlock()->ownerExecutable()->sourceID(), lastLine); return; } } @@ -927,10 +883,10 @@ NEVER_INLINE void Interpreter::debug(CallFrame* callFrame, DebugHookID debugHook #if USE(INTERPRETER) NEVER_INLINE ScopeChainNode* Interpreter::createExceptionScope(CallFrame* callFrame, const Instruction* vPC) { - int dst = (++vPC)->u.operand; + int dst = vPC[1].u.operand; CodeBlock* codeBlock = callFrame->codeBlock(); - Identifier& property = codeBlock->identifier((++vPC)->u.operand); - JSValue value = callFrame->r((++vPC)->u.operand).jsValue(); + Identifier& property = codeBlock->identifier(vPC[2].u.operand); + JSValue value = callFrame->r(vPC[3].u.operand).jsValue(); JSObject* scope = new (callFrame) JSStaticScopeObject(callFrame, property, value, DontDelete); callFrame->r(dst) = JSValue(scope); @@ -955,7 +911,7 @@ NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* JSCell* baseCell = asCell(baseValue); Structure* structure = baseCell->structure(); - if (structure->isDictionary()) { + if (structure->isUncacheableDictionary()) { vPC[0] = getOpcode(op_put_by_id_generic); return; } @@ -982,18 +938,20 @@ NEVER_INLINE void Interpreter::tryCachePutByID(CallFrame* callFrame, CodeBlock* return; } - StructureChain* protoChain = structure->prototypeChain(callFrame); - if (!protoChain->isCacheable()) { - vPC[0] = getOpcode(op_put_by_id_generic); - return; - } - // Structure transition, cache transition info if (slot.type() == PutPropertySlot::NewProperty) { + if (structure->isDictionary()) { + vPC[0] = getOpcode(op_put_by_id_generic); + return; + } + + // put_by_id_transition checks the prototype chain for setters. + normalizePrototypeChain(callFrame, baseCell); + vPC[0] = getOpcode(op_put_by_id_transition); vPC[4] = structure->previousID(); vPC[5] = structure; - vPC[6] = protoChain; + vPC[6] = structure->prototypeChain(callFrame); vPC[7] = slot.cachedOffset(); codeBlock->refStructures(vPC); return; @@ -1042,7 +1000,7 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* Structure* structure = asCell(baseValue)->structure(); - if (structure->isDictionary()) { + if (structure->isUncacheableDictionary()) { vPC[0] = getOpcode(op_get_by_id_generic); return; } @@ -1071,6 +1029,11 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* return; } + if (structure->isDictionary()) { + vPC[0] = getOpcode(op_get_by_id_generic); + return; + } + if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { ASSERT(slot.slotBase().isObject()); @@ -1079,7 +1042,9 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (baseObject->structure()->isDictionary()) - baseObject->setStructure(Structure::fromDictionaryTransition(baseObject->structure())); + baseObject->flattenDictionaryObject(); + + ASSERT(!baseObject->structure()->isUncacheableDictionary()); vPC[0] = getOpcode(op_get_by_id_proto); vPC[5] = baseObject->structure(); @@ -1089,21 +1054,15 @@ NEVER_INLINE void Interpreter::tryCacheGetByID(CallFrame* callFrame, CodeBlock* return; } - size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot); + size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase()); if (!count) { vPC[0] = getOpcode(op_get_by_id_generic); return; } - StructureChain* protoChain = structure->prototypeChain(callFrame); - if (!protoChain->isCacheable()) { - vPC[0] = getOpcode(op_get_by_id_generic); - return; - } - vPC[0] = getOpcode(op_get_by_id_chain); vPC[4] = structure; - vPC[5] = protoChain; + vPC[5] = structure->prototypeChain(callFrame); vPC[6] = count; vPC[7] = slot.cachedOffset(); codeBlock->refStructures(vPC); @@ -1208,10 +1167,10 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Constructs a new empty Object instance using the original constructor, and puts the result in register dst. */ - int dst = (++vPC)->u.operand; + int dst = vPC[1].u.operand; callFrame->r(dst) = JSValue(constructEmptyObject(callFrame)); - ++vPC; + vPC += OPCODE_LENGTH(op_new_object); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_new_array) { @@ -1222,13 +1181,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi The array will contain argCount elements with values taken from registers starting at register firstArg. */ - int dst = (++vPC)->u.operand; - int firstArg = (++vPC)->u.operand; - int argCount = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int firstArg = vPC[2].u.operand; + int argCount = vPC[3].u.operand; ArgList args(callFrame->registers() + firstArg, argCount); callFrame->r(dst) = JSValue(constructArray(callFrame, args)); - ++vPC; + vPC += OPCODE_LENGTH(op_new_array); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_new_regexp) { @@ -1238,11 +1197,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi constructor from regexp regExp, and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int regExp = (++vPC)->u.operand; - callFrame->r(dst) = JSValue(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject()->regExpStructure(), callFrame->codeBlock()->regexp(regExp))); + int dst = vPC[1].u.operand; + int regExp = vPC[2].u.operand; + callFrame->r(dst) = JSValue(new (globalData) RegExpObject(callFrame->scopeChain()->globalObject->regExpStructure(), callFrame->codeBlock()->regexp(regExp))); - ++vPC; + vPC += OPCODE_LENGTH(op_new_regexp); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_mov) { @@ -1250,11 +1209,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Copies register src to register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; callFrame->r(dst) = callFrame->r(src); - ++vPC; + vPC += OPCODE_LENGTH(op_mov); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_eq) { @@ -1264,9 +1223,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi as with the ECMAScript '==' operator, and puts the result as a boolean in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); if (src1.isInt32() && src2.isInt32()) callFrame->r(dst) = jsBoolean(src1.asInt32() == src2.asInt32()); else { @@ -1275,7 +1234,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_eq); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_eq_null) { @@ -1284,17 +1243,17 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Checks whether register src is null, as with the ECMAScript '!=' operator, and puts the result as a boolean in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src = callFrame->r(vPC[2].u.operand).jsValue(); if (src.isUndefinedOrNull()) { callFrame->r(dst) = jsBoolean(true); - ++vPC; + vPC += OPCODE_LENGTH(op_eq_null); NEXT_INSTRUCTION(); } callFrame->r(dst) = jsBoolean(src.isCell() && src.asCell()->structure()->typeInfo().masqueradesAsUndefined()); - ++vPC; + vPC += OPCODE_LENGTH(op_eq_null); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_neq) { @@ -1304,9 +1263,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi equal, as with the ECMAScript '!=' operator, and puts the result as a boolean in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); if (src1.isInt32() && src2.isInt32()) callFrame->r(dst) = jsBoolean(src1.asInt32() != src2.asInt32()); else { @@ -1315,7 +1274,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_neq); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_neq_null) { @@ -1324,17 +1283,17 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Checks whether register src is not null, as with the ECMAScript '!=' operator, and puts the result as a boolean in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src = callFrame->r(vPC[2].u.operand).jsValue(); if (src.isUndefinedOrNull()) { callFrame->r(dst) = jsBoolean(false); - ++vPC; + vPC += OPCODE_LENGTH(op_neq_null); NEXT_INSTRUCTION(); } callFrame->r(dst) = jsBoolean(!src.isCell() || !asCell(src)->structure()->typeInfo().masqueradesAsUndefined()); - ++vPC; + vPC += OPCODE_LENGTH(op_neq_null); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_stricteq) { @@ -1344,12 +1303,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi equal, as with the ECMAScript '===' operator, and puts the result as a boolean in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); - callFrame->r(dst) = jsBoolean(JSValue::strictEqual(src1, src2)); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); + callFrame->r(dst) = jsBoolean(JSValue::strictEqual(callFrame, src1, src2)); - ++vPC; + vPC += OPCODE_LENGTH(op_stricteq); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_nstricteq) { @@ -1359,12 +1318,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi strictly equal, as with the ECMAScript '!==' operator, and puts the result as a boolean in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); - callFrame->r(dst) = jsBoolean(!JSValue::strictEqual(src1, src2)); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); + callFrame->r(dst) = jsBoolean(!JSValue::strictEqual(callFrame, src1, src2)); - ++vPC; + vPC += OPCODE_LENGTH(op_nstricteq); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_less) { @@ -1374,14 +1333,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi with the ECMAScript '<' operator, and puts the result as a boolean in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); JSValue result = jsBoolean(jsLess(callFrame, src1, src2)); CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; - ++vPC; + vPC += OPCODE_LENGTH(op_less); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_lesseq) { @@ -1391,14 +1350,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi register src2, as with the ECMAScript '<=' operator, and puts the result as a boolean in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); JSValue result = jsBoolean(jsLessEq(callFrame, src1, src2)); CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; - ++vPC; + vPC += OPCODE_LENGTH(op_lesseq); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_pre_inc) { @@ -1407,7 +1366,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Converts register srcDst to number, adds one, and puts the result back in register srcDst. */ - int srcDst = (++vPC)->u.operand; + int srcDst = vPC[1].u.operand; JSValue v = callFrame->r(srcDst).jsValue(); if (v.isInt32() && v.asInt32() < INT_MAX) callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1); @@ -1417,7 +1376,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(srcDst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_pre_inc); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_pre_dec) { @@ -1426,7 +1385,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Converts register srcDst to number, subtracts one, and puts the result back in register srcDst. */ - int srcDst = (++vPC)->u.operand; + int srcDst = vPC[1].u.operand; JSValue v = callFrame->r(srcDst).jsValue(); if (v.isInt32() && v.asInt32() > INT_MIN) callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1); @@ -1436,7 +1395,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(srcDst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_pre_dec); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_post_inc) { @@ -1446,8 +1405,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi written to register dst, and the number plus one is written back to register srcDst. */ - int dst = (++vPC)->u.operand; - int srcDst = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int srcDst = vPC[2].u.operand; JSValue v = callFrame->r(srcDst).jsValue(); if (v.isInt32() && v.asInt32() < INT_MAX) { callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() + 1); @@ -1459,7 +1418,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = number; } - ++vPC; + vPC += OPCODE_LENGTH(op_post_inc); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_post_dec) { @@ -1469,8 +1428,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi written to register dst, and the number minus one is written back to register srcDst. */ - int dst = (++vPC)->u.operand; - int srcDst = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int srcDst = vPC[2].u.operand; JSValue v = callFrame->r(srcDst).jsValue(); if (v.isInt32() && v.asInt32() > INT_MIN) { callFrame->r(srcDst) = jsNumber(callFrame, v.asInt32() - 1); @@ -1482,7 +1441,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = number; } - ++vPC; + vPC += OPCODE_LENGTH(op_post_dec); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_to_jsnumber) { @@ -1491,8 +1450,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Converts register src to number, and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; JSValue srcVal = callFrame->r(src).jsValue(); @@ -1504,7 +1463,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_to_jsnumber); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_negate) { @@ -1513,8 +1472,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Converts register src to number, negates it, and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src = callFrame->r(vPC[2].u.operand).jsValue(); if (src.isInt32() && src.asInt32()) callFrame->r(dst) = jsNumber(callFrame, -src.asInt32()); else { @@ -1523,7 +1482,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_negate); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_add) { @@ -1533,17 +1492,17 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi in register dst. (JS add may be string concatenation or numeric add, depending on the types of the operands.) */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); - if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() & 0xc0000000)) // no overflow + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); + if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() + src2.asInt32()); else { JSValue result = jsAdd(callFrame, src1, src2); CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; } - vPC += 2; + vPC += OPCODE_LENGTH(op_add); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_mul) { @@ -1552,9 +1511,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Multiplies register src1 and register src2 (converted to numbers), and puts the product in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() >> 15)) // no overflow callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() * src2.asInt32()); else { @@ -1563,7 +1522,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - vPC += 2; + vPC += OPCODE_LENGTH(op_mul); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_div) { @@ -1573,15 +1532,15 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi register divisor (converted to number), and puts the quotient in register dst. */ - int dst = (++vPC)->u.operand; - JSValue dividend = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue divisor = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue(); JSValue result = jsNumber(callFrame, dividend.toNumber(callFrame) / divisor.toNumber(callFrame)); CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; - vPC += 2; + vPC += OPCODE_LENGTH(op_div); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_mod) { @@ -1591,15 +1550,15 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi register divisor (converted to number), and puts the remainder in register dst. */ - int dst = (++vPC)->u.operand; - JSValue dividend = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue divisor = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue dividend = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue divisor = callFrame->r(vPC[3].u.operand).jsValue(); if (dividend.isInt32() && divisor.isInt32() && divisor.asInt32() != 0) { JSValue result = jsNumber(callFrame, dividend.asInt32() % divisor.asInt32()); ASSERT(result); callFrame->r(dst) = result; - ++vPC; + vPC += OPCODE_LENGTH(op_mod); NEXT_INSTRUCTION(); } @@ -1610,7 +1569,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSValue result = jsNumber(callFrame, fmod(d1, d2)); CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; - ++vPC; + vPC += OPCODE_LENGTH(op_mod); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_sub) { @@ -1620,17 +1579,17 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi src1 (converted to number), and puts the difference in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); - if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | src2.asInt32() & 0xc0000000)) // no overflow + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); + if (src1.isInt32() && src2.isInt32() && !(src1.asInt32() | (src2.asInt32() & 0xc0000000))) // no overflow callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() - src2.asInt32()); else { JSValue result = jsNumber(callFrame, src1.toNumber(callFrame) - src2.toNumber(callFrame)); CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; } - vPC += 2; + vPC += OPCODE_LENGTH(op_sub); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_lshift) { @@ -1640,9 +1599,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi register shift (converted to uint32), and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - JSValue val = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue shift = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue val = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue shift = callFrame->r(vPC[3].u.operand).jsValue(); if (val.isInt32() && shift.isInt32()) callFrame->r(dst) = jsNumber(callFrame, val.asInt32() << (shift.asInt32() & 0x1f)); @@ -1652,7 +1611,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_lshift); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_rshift) { @@ -1662,9 +1621,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi to int32) by register shift (converted to uint32), and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - JSValue val = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue shift = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue val = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue shift = callFrame->r(vPC[3].u.operand).jsValue(); if (val.isInt32() && shift.isInt32()) callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f)); @@ -1674,7 +1633,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_rshift); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_urshift) { @@ -1684,9 +1643,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi to uint32) by register shift (converted to uint32), and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - JSValue val = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue shift = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue val = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue shift = callFrame->r(vPC[3].u.operand).jsValue(); if (val.isUInt32() && shift.isInt32()) callFrame->r(dst) = jsNumber(callFrame, val.asInt32() >> (shift.asInt32() & 0x1f)); else { @@ -1695,7 +1654,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_urshift); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_bitand) { @@ -1705,9 +1664,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi and register src2 (converted to int32), and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); if (src1.isInt32() && src2.isInt32()) callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() & src2.asInt32()); else { @@ -1716,7 +1675,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - vPC += 2; + vPC += OPCODE_LENGTH(op_bitand); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_bitxor) { @@ -1726,9 +1685,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi and register src2 (converted to int32), and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); if (src1.isInt32() && src2.isInt32()) callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() ^ src2.asInt32()); else { @@ -1737,7 +1696,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - vPC += 2; + vPC += OPCODE_LENGTH(op_bitxor); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_bitor) { @@ -1747,9 +1706,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi and register src2 (converted to int32), and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src1 = callFrame->r(vPC[2].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[3].u.operand).jsValue(); if (src1.isInt32() && src2.isInt32()) callFrame->r(dst) = jsNumber(callFrame, src1.asInt32() | src2.asInt32()); else { @@ -1758,7 +1717,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = result; } - vPC += 2; + vPC += OPCODE_LENGTH(op_bitor); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_bitnot) { @@ -1767,8 +1726,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Computes bitwise NOT of register src1 (converted to int32), and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - JSValue src = callFrame->r((++vPC)->u.operand).jsValue(); + int dst = vPC[1].u.operand; + JSValue src = callFrame->r(vPC[2].u.operand).jsValue(); if (src.isInt32()) callFrame->r(dst) = jsNumber(callFrame, ~src.asInt32()); else { @@ -1776,7 +1735,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; } - ++vPC; + vPC += OPCODE_LENGTH(op_bitnot); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_not) { @@ -1785,13 +1744,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Computes logical NOT of register src (converted to boolean), and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; JSValue result = jsBoolean(!callFrame->r(src).jsValue().toBoolean(callFrame)); CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; - ++vPC; + vPC += OPCODE_LENGTH(op_not); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_instanceof) { @@ -1821,7 +1780,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi CHECK_FOR_EXCEPTION(); callFrame->r(dst) = jsBoolean(result); - vPC += 5; + vPC += OPCODE_LENGTH(op_instanceof); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_typeof) { @@ -1830,11 +1789,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Determines the type string for src according to ECMAScript rules, and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; callFrame->r(dst) = JSValue(jsTypeStringForValue(callFrame, callFrame->r(src).jsValue())); - ++vPC; + vPC += OPCODE_LENGTH(op_typeof); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_is_undefined) { @@ -1844,12 +1803,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi the ECMAScript rules is "undefined", and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; JSValue v = callFrame->r(src).jsValue(); callFrame->r(dst) = jsBoolean(v.isCell() ? v.asCell()->structure()->typeInfo().masqueradesAsUndefined() : v.isUndefined()); - ++vPC; + vPC += OPCODE_LENGTH(op_is_undefined); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_is_boolean) { @@ -1859,11 +1818,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi the ECMAScript rules is "boolean", and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isBoolean()); - ++vPC; + vPC += OPCODE_LENGTH(op_is_boolean); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_is_number) { @@ -1873,11 +1832,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi the ECMAScript rules is "number", and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isNumber()); - ++vPC; + vPC += OPCODE_LENGTH(op_is_number); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_is_string) { @@ -1887,11 +1846,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi the ECMAScript rules is "string", and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; callFrame->r(dst) = jsBoolean(callFrame->r(src).jsValue().isString()); - ++vPC; + vPC += OPCODE_LENGTH(op_is_string); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_is_object) { @@ -1901,11 +1860,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi the ECMAScript rules is "object", and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; callFrame->r(dst) = jsBoolean(jsIsObjectType(callFrame->r(src).jsValue())); - ++vPC; + vPC += OPCODE_LENGTH(op_is_object); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_is_function) { @@ -1915,11 +1874,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi the ECMAScript rules is "function", and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; callFrame->r(dst) = jsBoolean(jsIsFunctionType(callFrame->r(src).jsValue())); - ++vPC; + vPC += OPCODE_LENGTH(op_is_function); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_in) { @@ -1931,9 +1890,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Raises an exception if register constructor is not an object. */ - int dst = (++vPC)->u.operand; - int property = (++vPC)->u.operand; - int base = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int property = vPC[2].u.operand; + int base = vPC[3].u.operand; JSValue baseVal = callFrame->r(base).jsValue(); if (isInvalidParamForIn(callFrame, callFrame->codeBlock(), vPC, baseVal, exceptionValue)) @@ -1952,7 +1911,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(dst) = jsBoolean(baseObj->hasProperty(callFrame, property)); } - ++vPC; + vPC += OPCODE_LENGTH(op_in); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_resolve) { @@ -1965,7 +1924,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (UNLIKELY(!resolve(callFrame, vPC, exceptionValue))) goto vm_throw; - vPC += 3; + vPC += OPCODE_LENGTH(op_resolve); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_resolve_skip) { @@ -1978,7 +1937,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (UNLIKELY(!resolveSkip(callFrame, vPC, exceptionValue))) goto vm_throw; - vPC += 4; + vPC += OPCODE_LENGTH(op_resolve_skip); NEXT_INSTRUCTION(); } @@ -1993,7 +1952,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (UNLIKELY(!resolveGlobal(callFrame, vPC, exceptionValue))) goto vm_throw; - vPC += 6; + vPC += OPCODE_LENGTH(op_resolve_global); NEXT_INSTRUCTION(); } @@ -2002,13 +1961,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Gets the global var at global slot index and places it in register dst. */ - int dst = (++vPC)->u.operand; - JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell); + int dst = vPC[1].u.operand; + JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[2].u.jsCell); ASSERT(scope->isGlobalObject()); - int index = (++vPC)->u.operand; + int index = vPC[3].u.operand; callFrame->r(dst) = scope->registerAt(index); - ++vPC; + vPC += OPCODE_LENGTH(op_get_global_var); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_put_global_var) { @@ -2016,13 +1975,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Puts value into global slot index. */ - JSGlobalObject* scope = static_cast<JSGlobalObject*>((++vPC)->u.jsCell); + JSGlobalObject* scope = static_cast<JSGlobalObject*>(vPC[1].u.jsCell); ASSERT(scope->isGlobalObject()); - int index = (++vPC)->u.operand; - int value = (++vPC)->u.operand; + int index = vPC[2].u.operand; + int value = vPC[3].u.operand; scope->registerAt(index) = JSValue(callFrame->r(value).jsValue()); - ++vPC; + vPC += OPCODE_LENGTH(op_put_global_var); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_scoped_var) { @@ -2031,9 +1990,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Loads the contents of the index-th local from the scope skip nodes from the top of the scope chain, and places it in register dst */ - int dst = (++vPC)->u.operand; - int index = (++vPC)->u.operand; - int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain(); + int dst = vPC[1].u.operand; + int index = vPC[2].u.operand; + int skip = vPC[3].u.operand + callFrame->codeBlock()->needsFullScopeChain(); ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); @@ -2047,16 +2006,16 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT((*iter)->isVariableObject()); JSVariableObject* scope = static_cast<JSVariableObject*>(*iter); callFrame->r(dst) = scope->registerAt(index); - ++vPC; + vPC += OPCODE_LENGTH(op_get_scoped_var); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_put_scoped_var) { /* put_scoped_var index(n) skip(n) value(r) */ - int index = (++vPC)->u.operand; - int skip = (++vPC)->u.operand + callFrame->codeBlock()->needsFullScopeChain(); - int value = (++vPC)->u.operand; + int index = vPC[1].u.operand; + int skip = vPC[2].u.operand + callFrame->codeBlock()->needsFullScopeChain(); + int value = vPC[3].u.operand; ScopeChainNode* scopeChain = callFrame->scopeChain(); ScopeChainIterator iter = scopeChain->begin(); @@ -2070,7 +2029,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT((*iter)->isVariableObject()); JSVariableObject* scope = static_cast<JSVariableObject*>(*iter); scope->registerAt(index) = JSValue(callFrame->r(value).jsValue()); - ++vPC; + vPC += OPCODE_LENGTH(op_put_scoped_var); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_resolve_base) { @@ -2083,7 +2042,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi */ resolveBase(callFrame, vPC); - vPC += 3; + vPC += OPCODE_LENGTH(op_resolve_base); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_resolve_with_base) { @@ -2101,7 +2060,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (UNLIKELY(!resolveBaseAndProperty(callFrame, vPC, exceptionValue))) goto vm_throw; - vPC += 4; + vPC += OPCODE_LENGTH(op_resolve_with_base); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_by_id) { @@ -2124,7 +2083,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi tryCacheGetByID(callFrame, codeBlock, vPC, baseValue, ident, slot); callFrame->r(dst) = result; - vPC += 8; + vPC += OPCODE_LENGTH(op_get_by_id); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_by_id_self) { @@ -2150,7 +2109,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset)); callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset)); - vPC += 8; + vPC += OPCODE_LENGTH(op_get_by_id_self); NEXT_INSTRUCTION(); } } @@ -2182,9 +2141,10 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int offset = vPC[6].u.operand; ASSERT(protoObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset)); + ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == protoObject->getDirectOffset(offset)); callFrame->r(dst) = JSValue(protoObject->getDirectOffset(offset)); - vPC += 8; + vPC += OPCODE_LENGTH(op_get_by_id_proto); NEXT_INSTRUCTION(); } } @@ -2197,14 +2157,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi // Polymorphic self access caching currently only supported when JITting. ASSERT_NOT_REACHED(); // This case of the switch must not be empty, else (op_get_by_id_self_list == op_get_by_id_chain)! - vPC += 8; + vPC += OPCODE_LENGTH(op_get_by_id_self_list); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_by_id_proto_list) { // Polymorphic prototype access caching currently only supported when JITting. ASSERT_NOT_REACHED(); // This case of the switch must not be empty, else (op_get_by_id_proto_list == op_get_by_id_chain)! - vPC += 8; + vPC += OPCODE_LENGTH(op_get_by_id_proto_list); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_by_id_chain) { @@ -2237,9 +2197,10 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int offset = vPC[7].u.operand; ASSERT(baseObject->get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset)); + ASSERT(baseValue.get(callFrame, callFrame->codeBlock()->identifier(vPC[3].u.operand)) == baseObject->getDirectOffset(offset)); callFrame->r(dst) = JSValue(baseObject->getDirectOffset(offset)); - vPC += 8; + vPC += OPCODE_LENGTH(op_get_by_id_chain); NEXT_INSTRUCTION(); } @@ -2269,7 +2230,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; - vPC += 8; + vPC += OPCODE_LENGTH(op_get_by_id_generic); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_array_length) { @@ -2285,7 +2246,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (LIKELY(isJSArray(globalData, baseValue))) { int dst = vPC[1].u.operand; callFrame->r(dst) = jsNumber(callFrame, asArray(baseValue)->length()); - vPC += 8; + vPC += OPCODE_LENGTH(op_get_array_length); NEXT_INSTRUCTION(); } @@ -2304,8 +2265,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSValue baseValue = callFrame->r(base).jsValue(); if (LIKELY(isJSString(globalData, baseValue))) { int dst = vPC[1].u.operand; - callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->value().size()); - vPC += 8; + callFrame->r(dst) = jsNumber(callFrame, asString(baseValue)->length()); + vPC += OPCODE_LENGTH(op_get_string_length); NEXT_INSTRUCTION(); } @@ -2335,7 +2296,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi tryCachePutByID(callFrame, codeBlock, vPC, baseValue, slot); - vPC += 8; + vPC += OPCODE_LENGTH(op_put_by_id); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_put_by_id_transition) { @@ -2380,7 +2341,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset); baseObject->putDirectOffset(offset, callFrame->r(value).jsValue()); - vPC += 8; + vPC += OPCODE_LENGTH(op_put_by_id_transition); NEXT_INSTRUCTION(); } } @@ -2415,7 +2376,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT(baseObject->offsetForLocation(baseObject->getDirectLocation(callFrame->codeBlock()->identifier(vPC[2].u.operand))) == offset); baseObject->putDirectOffset(offset, callFrame->r(value).jsValue()); - vPC += 8; + vPC += OPCODE_LENGTH(op_put_by_id_replace); NEXT_INSTRUCTION(); } } @@ -2442,7 +2403,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi baseValue.put(callFrame, ident, callFrame->r(value).jsValue(), slot); CHECK_FOR_EXCEPTION(); - vPC += 8; + vPC += OPCODE_LENGTH(op_put_by_id_generic); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_del_by_id) { @@ -2453,16 +2414,43 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi boolean indicating success (if true) or failure (if false) to register dst. */ - int dst = (++vPC)->u.operand; - int base = (++vPC)->u.operand; - int property = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int base = vPC[2].u.operand; + int property = vPC[3].u.operand; JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); Identifier& ident = callFrame->codeBlock()->identifier(property); JSValue result = jsBoolean(baseObj->deleteProperty(callFrame, ident)); CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; - ++vPC; + vPC += OPCODE_LENGTH(op_del_by_id); + NEXT_INSTRUCTION(); + } + DEFINE_OPCODE(op_get_by_pname) { + int dst = vPC[1].u.operand; + int base = vPC[2].u.operand; + int property = vPC[3].u.operand; + int expected = vPC[4].u.operand; + int iter = vPC[5].u.operand; + int i = vPC[6].u.operand; + + JSValue baseValue = callFrame->r(base).jsValue(); + JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator(); + JSValue subscript = callFrame->r(property).jsValue(); + JSValue expectedSubscript = callFrame->r(expected).jsValue(); + int index = callFrame->r(i).i() - 1; + JSValue result; + int offset = 0; + if (subscript == expectedSubscript && baseValue.isCell() && (baseValue.asCell()->structure() == it->cachedStructure()) && it->getOffset(index, offset)) { + callFrame->r(dst) = asObject(baseValue)->getDirectOffset(offset); + vPC += OPCODE_LENGTH(op_get_by_pname); + NEXT_INSTRUCTION(); + } + Identifier propertyName(callFrame, subscript.toString(callFrame)); + result = baseValue.get(callFrame, propertyName); + CHECK_FOR_EXCEPTION(); + callFrame->r(dst) = result; + vPC += OPCODE_LENGTH(op_get_by_pname); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_by_val) { @@ -2473,9 +2461,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi in register dst. property is nominally converted to string but numbers are treated more efficiently. */ - int dst = (++vPC)->u.operand; - int base = (++vPC)->u.operand; - int property = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int base = vPC[2].u.operand; + int property = vPC[3].u.operand; JSValue baseValue = callFrame->r(base).jsValue(); JSValue subscript = callFrame->r(property).jsValue(); @@ -2491,7 +2479,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi else result = jsArray->JSArray::get(callFrame, i); } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) - result = asString(baseValue)->getIndex(&callFrame->globalData(), i); + result = asString(baseValue)->getIndex(callFrame, i); else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) result = asByteArray(baseValue)->getIndex(callFrame, i); else @@ -2503,7 +2491,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; - ++vPC; + vPC += OPCODE_LENGTH(op_get_by_val); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_put_by_val) { @@ -2517,9 +2505,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Unlike many opcodes, this one does not write any output to the register file. */ - int base = (++vPC)->u.operand; - int property = (++vPC)->u.operand; - int value = (++vPC)->u.operand; + int base = vPC[1].u.operand; + int property = vPC[2].u.operand; + int value = vPC[3].u.operand; JSValue baseValue = callFrame->r(base).jsValue(); JSValue subscript = callFrame->r(property).jsValue(); @@ -2553,7 +2541,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi } CHECK_FOR_EXCEPTION(); - ++vPC; + vPC += OPCODE_LENGTH(op_put_by_val); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_del_by_val) { @@ -2564,9 +2552,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi boolean indicating success (if true) or failure (if false) to register dst. */ - int dst = (++vPC)->u.operand; - int base = (++vPC)->u.operand; - int property = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int base = vPC[2].u.operand; + int property = vPC[3].u.operand; JSObject* baseObj = callFrame->r(base).jsValue().toObject(callFrame); // may throw @@ -2584,7 +2572,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi CHECK_FOR_EXCEPTION(); callFrame->r(dst) = result; - ++vPC; + vPC += OPCODE_LENGTH(op_del_by_val); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_put_by_index) { @@ -2599,13 +2587,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi This opcode is mainly used to initialize array literals. */ - int base = (++vPC)->u.operand; - unsigned property = (++vPC)->u.operand; - int value = (++vPC)->u.operand; + int base = vPC[1].u.operand; + unsigned property = vPC[2].u.operand; + int value = vPC[3].u.operand; callFrame->r(base).jsValue().put(callFrame, property, callFrame->r(value).jsValue()); - ++vPC; + vPC += OPCODE_LENGTH(op_put_by_index); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_loop) { @@ -2620,7 +2608,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi #if ENABLE(OPCODE_STATS) OpcodeStats::resetLastInstruction(); #endif - int target = (++vPC)->u.operand; + int target = vPC[1].u.operand; CHECK_FOR_TIMEOUT(); vPC += target; NEXT_INSTRUCTION(); @@ -2634,7 +2622,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi #if ENABLE(OPCODE_STATS) OpcodeStats::resetLastInstruction(); #endif - int target = (++vPC)->u.operand; + int target = vPC[1].u.operand; vPC += target; NEXT_INSTRUCTION(); @@ -2648,15 +2636,35 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Additionally this loop instruction may terminate JS execution is the JS timeout is reached. */ - int cond = (++vPC)->u.operand; - int target = (++vPC)->u.operand; + int cond = vPC[1].u.operand; + int target = vPC[2].u.operand; if (callFrame->r(cond).jsValue().toBoolean(callFrame)) { vPC += target; CHECK_FOR_TIMEOUT(); NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_loop_if_true); + NEXT_INSTRUCTION(); + } + DEFINE_OPCODE(op_loop_if_false) { + /* loop_if_true cond(r) target(offset) + + Jumps to offset target from the current instruction, if and + only if register cond converts to boolean as false. + + Additionally this loop instruction may terminate JS execution is + the JS timeout is reached. + */ + int cond = vPC[1].u.operand; + int target = vPC[2].u.operand; + if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) { + vPC += target; + CHECK_FOR_TIMEOUT(); + NEXT_INSTRUCTION(); + } + + vPC += OPCODE_LENGTH(op_loop_if_true); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_jtrue) { @@ -2665,14 +2673,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Jumps to offset target from the current instruction, if and only if register cond converts to boolean as true. */ - int cond = (++vPC)->u.operand; - int target = (++vPC)->u.operand; + int cond = vPC[1].u.operand; + int target = vPC[2].u.operand; if (callFrame->r(cond).jsValue().toBoolean(callFrame)) { vPC += target; NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_jtrue); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_jfalse) { @@ -2681,14 +2689,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Jumps to offset target from the current instruction, if and only if register cond converts to boolean as false. */ - int cond = (++vPC)->u.operand; - int target = (++vPC)->u.operand; + int cond = vPC[1].u.operand; + int target = vPC[2].u.operand; if (!callFrame->r(cond).jsValue().toBoolean(callFrame)) { vPC += target; NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_jfalse); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_jeq_null) { @@ -2697,8 +2705,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Jumps to offset target from the current instruction, if and only if register src is null. */ - int src = (++vPC)->u.operand; - int target = (++vPC)->u.operand; + int src = vPC[1].u.operand; + int target = vPC[2].u.operand; JSValue srcValue = callFrame->r(src).jsValue(); if (srcValue.isUndefinedOrNull() || (srcValue.isCell() && srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) { @@ -2706,7 +2714,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_jeq_null); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_jneq_null) { @@ -2715,16 +2723,16 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Jumps to offset target from the current instruction, if and only if register src is not null. */ - int src = (++vPC)->u.operand; - int target = (++vPC)->u.operand; + int src = vPC[1].u.operand; + int target = vPC[2].u.operand; JSValue srcValue = callFrame->r(src).jsValue(); - if (!srcValue.isUndefinedOrNull() || (srcValue.isCell() && !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) { + if (!srcValue.isUndefinedOrNull() && (!srcValue.isCell() || !srcValue.asCell()->structure()->typeInfo().masqueradesAsUndefined())) { vPC += target; NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_jneq_null); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_jneq_ptr) { @@ -2733,16 +2741,16 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Jumps to offset target from the current instruction, if the value r is equal to ptr, using pointer equality. */ - int src = (++vPC)->u.operand; - JSValue ptr = JSValue((++vPC)->u.jsCell); - int target = (++vPC)->u.operand; + int src = vPC[1].u.operand; + JSValue ptr = JSValue(vPC[2].u.jsCell); + int target = vPC[3].u.operand; JSValue srcValue = callFrame->r(src).jsValue(); if (srcValue != ptr) { vPC += target; NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_jneq_ptr); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_loop_if_less) { @@ -2756,9 +2764,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Additionally this loop instruction may terminate JS execution is the JS timeout is reached. */ - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); - int target = (++vPC)->u.operand; + JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); + int target = vPC[3].u.operand; bool result = jsLess(callFrame, src1, src2); CHECK_FOR_EXCEPTION(); @@ -2769,7 +2777,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_loop_if_less); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_loop_if_lesseq) { @@ -2783,9 +2791,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Additionally this loop instruction may terminate JS execution is the JS timeout is reached. */ - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); - int target = (++vPC)->u.operand; + JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); + int target = vPC[3].u.operand; bool result = jsLessEq(callFrame, src1, src2); CHECK_FOR_EXCEPTION(); @@ -2796,7 +2804,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_loop_if_lesseq); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_jnless) { @@ -2807,9 +2815,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi target from the current instruction, if and only if the result of the comparison is false. */ - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); - int target = (++vPC)->u.operand; + JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); + int target = vPC[3].u.operand; bool result = jsLess(callFrame, src1, src2); CHECK_FOR_EXCEPTION(); @@ -2819,7 +2827,30 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_jnless); + NEXT_INSTRUCTION(); + } + DEFINE_OPCODE(op_jless) { + /* jless src1(r) src2(r) target(offset) + + Checks whether register src1 is less than register src2, as + with the ECMAScript '<' operator, and then jumps to offset + target from the current instruction, if and only if the + result of the comparison is true. + */ + JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); + int target = vPC[3].u.operand; + + bool result = jsLess(callFrame, src1, src2); + CHECK_FOR_EXCEPTION(); + + if (result) { + vPC += target; + NEXT_INSTRUCTION(); + } + + vPC += OPCODE_LENGTH(op_jless); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_jnlesseq) { @@ -2830,9 +2861,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi and then jumps to offset target from the current instruction, if and only if theresult of the comparison is false. */ - JSValue src1 = callFrame->r((++vPC)->u.operand).jsValue(); - JSValue src2 = callFrame->r((++vPC)->u.operand).jsValue(); - int target = (++vPC)->u.operand; + JSValue src1 = callFrame->r(vPC[1].u.operand).jsValue(); + JSValue src2 = callFrame->r(vPC[2].u.operand).jsValue(); + int target = vPC[3].u.operand; bool result = jsLessEq(callFrame, src1, src2); CHECK_FOR_EXCEPTION(); @@ -2842,7 +2873,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi NEXT_INSTRUCTION(); } - ++vPC; + vPC += OPCODE_LENGTH(op_jnlesseq); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_switch_imm) { @@ -2854,9 +2885,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi table, and the value at jumpTable[scrutinee value] is non-zero, then that value is used as the jump offset, otherwise defaultOffset is used. */ - int tableIndex = (++vPC)->u.operand; - int defaultOffset = (++vPC)->u.operand; - JSValue scrutinee = callFrame->r((++vPC)->u.operand).jsValue(); + int tableIndex = vPC[1].u.operand; + int defaultOffset = vPC[2].u.operand; + JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue(); if (scrutinee.isInt32()) vPC += callFrame->codeBlock()->immediateSwitchJumpTable(tableIndex).offsetForValue(scrutinee.asInt32(), defaultOffset); else { @@ -2878,13 +2909,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi table, and the value at jumpTable[scrutinee value] is non-zero, then that value is used as the jump offset, otherwise defaultOffset is used. */ - int tableIndex = (++vPC)->u.operand; - int defaultOffset = (++vPC)->u.operand; - JSValue scrutinee = callFrame->r((++vPC)->u.operand).jsValue(); + int tableIndex = vPC[1].u.operand; + int defaultOffset = vPC[2].u.operand; + JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue(); if (!scrutinee.isString()) vPC += defaultOffset; else { - UString::Rep* value = asString(scrutinee)->value().rep(); + UString::Rep* value = asString(scrutinee)->value(callFrame).rep(); if (value->size() != 1) vPC += defaultOffset; else @@ -2901,13 +2932,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi jump table, then the value associated with the string is used as the jump offset, otherwise defaultOffset is used. */ - int tableIndex = (++vPC)->u.operand; - int defaultOffset = (++vPC)->u.operand; - JSValue scrutinee = callFrame->r((++vPC)->u.operand).jsValue(); + int tableIndex = vPC[1].u.operand; + int defaultOffset = vPC[2].u.operand; + JSValue scrutinee = callFrame->r(vPC[3].u.operand).jsValue(); if (!scrutinee.isString()) vPC += defaultOffset; else - vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value().rep(), defaultOffset); + vPC += callFrame->codeBlock()->stringSwitchJumpTable(tableIndex).offsetForValue(asString(scrutinee)->value(callFrame).rep(), defaultOffset); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_new_func) { @@ -2918,12 +2949,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi constructor, using the rules for function declarations, and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int func = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int func = vPC[2].u.operand; - callFrame->r(dst) = JSValue(callFrame->codeBlock()->function(func)->makeFunction(callFrame, callFrame->scopeChain())); + callFrame->r(dst) = JSValue(callFrame->codeBlock()->functionDecl(func)->make(callFrame, callFrame->scopeChain())); - ++vPC; + vPC += OPCODE_LENGTH(op_new_func); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_new_func_exp) { @@ -2934,12 +2965,27 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi constructor, using the rules for function expressions, and puts the result in register dst. */ - int dst = (++vPC)->u.operand; - int func = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int funcIndex = vPC[2].u.operand; - callFrame->r(dst) = JSValue(callFrame->codeBlock()->functionExpression(func)->makeFunction(callFrame, callFrame->scopeChain())); + FunctionExecutable* function = callFrame->codeBlock()->functionExpr(funcIndex); + JSFunction* func = function->make(callFrame, callFrame->scopeChain()); - ++vPC; + /* + 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 (!function->name().isNull()) { + JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete); + func->scope().push(functionScopeObject); + } + + callFrame->r(dst) = JSValue(func); + + vPC += OPCODE_LENGTH(op_new_func_exp); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_call_eval) { @@ -2964,7 +3010,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Register* newCallFrame = callFrame->registers() + registerOffset; Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount; JSValue thisValue = argv[0].jsValue(); - JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject(); + JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject; if (thisValue == globalObject && funcVal == globalObject->evalFunction()) { JSValue result = callEval(callFrame, registerFile, argv, argCount, registerOffset, exceptionValue); @@ -2972,7 +3018,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi goto vm_throw; callFrame->r(dst) = result; - vPC += 5; + vPC += OPCODE_LENGTH(op_call_eval); NEXT_INSTRUCTION(); } @@ -3003,8 +3049,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (callType == CallTypeJS) { ScopeChainNode* callDataScopeChain = callData.js.scopeChain; - FunctionBodyNode* functionBodyNode = callData.js.functionBody; - CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain); + CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain); CallFrame* previousCallFrame = callFrame; @@ -3040,14 +3085,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSValue returnValue; { - SamplingTool::HostCallRecord callRecord(m_sampler); + SamplingTool::HostCallRecord callRecord(m_sampler.get()); returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args); } CHECK_FOR_EXCEPTION(); callFrame->r(dst) = returnValue; - vPC += 5; + vPC += OPCODE_LENGTH(op_call); NEXT_INSTRUCTION(); } @@ -3057,8 +3102,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi goto vm_throw; } DEFINE_OPCODE(op_load_varargs) { - int argCountDst = (++vPC)->u.operand; - int argsOffset = (++vPC)->u.operand; + int argCountDst = vPC[1].u.operand; + int argsOffset = vPC[2].u.operand; JSValue arguments = callFrame->r(argsOffset).jsValue(); int32_t argCount = 0; @@ -3070,7 +3115,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi exceptionValue = createStackOverflowError(callFrame); goto vm_throw; } - int32_t expectedParams = callFrame->callee()->body()->parameterCount(); + ASSERT(!callFrame->callee()->isHostFunction()); + int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount(); int32_t inplaceArgs = min(argCount, expectedParams); int32_t i = 0; Register* argStore = callFrame->registers() + argsOffset; @@ -3129,7 +3175,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi } CHECK_FOR_EXCEPTION(); callFrame->r(argCountDst) = Register::withInt(argCount + 1); - ++vPC; + vPC += OPCODE_LENGTH(op_load_varargs); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_call_varargs) { @@ -3157,8 +3203,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (callType == CallTypeJS) { ScopeChainNode* callDataScopeChain = callData.js.scopeChain; - FunctionBodyNode* functionBodyNode = callData.js.functionBody; - CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain); + CodeBlock* newCodeBlock = &callData.js.functionExecutable->bytecode(callFrame, callDataScopeChain); CallFrame* previousCallFrame = callFrame; @@ -3194,14 +3239,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSValue returnValue; { - SamplingTool::HostCallRecord callRecord(m_sampler); + SamplingTool::HostCallRecord callRecord(m_sampler.get()); returnValue = callData.native.function(newCallFrame, asObject(v), thisValue, args); } CHECK_FOR_EXCEPTION(); callFrame->r(dst) = returnValue; - vPC += 5; + vPC += OPCODE_LENGTH(op_call_varargs); NEXT_INSTRUCTION(); } @@ -3223,12 +3268,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi This opcode should only be used immediately before op_ret. */ - int src = (++vPC)->u.operand; + int src = vPC[1].u.operand; ASSERT(callFrame->codeBlock()->needsFullScopeChain()); asActivation(callFrame->r(src).jsValue())->copyRegisters(callFrame->optionalCalleeArguments()); - ++vPC; + vPC += OPCODE_LENGTH(op_tear_off_activation); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_tear_off_arguments) { @@ -3249,7 +3294,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (callFrame->optionalCalleeArguments()) callFrame->optionalCalleeArguments()->copyRegisters(); - ++vPC; + vPC += OPCODE_LENGTH(op_tear_off_arguments); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_ret) { @@ -3262,7 +3307,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi register base to those of the calling function. */ - int result = (++vPC)->u.operand; + int result = vPC[1].u.operand; if (callFrame->codeBlock()->needsFullScopeChain()) callFrame->scopeChain()->deref(); @@ -3297,7 +3342,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi for (size_t count = codeBlock->m_numVars; i < count; ++i) callFrame->r(i) = jsUndefined(); - ++vPC; + vPC += OPCODE_LENGTH(op_enter); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_enter_with_activation) { @@ -3319,12 +3364,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi for (size_t count = codeBlock->m_numVars; i < count; ++i) callFrame->r(i) = jsUndefined(); - int dst = (++vPC)->u.operand; - JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionBodyNode*>(codeBlock->ownerNode())); + int dst = vPC[1].u.operand; + JSActivation* activation = new (globalData) JSActivation(callFrame, static_cast<FunctionExecutable*>(codeBlock->ownerExecutable())); callFrame->r(dst) = JSValue(activation); callFrame->setScopeChain(callFrame->scopeChain()->copy()->push(activation)); - ++vPC; + vPC += OPCODE_LENGTH(op_enter_with_activation); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_convert_this) { @@ -3339,12 +3384,12 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi block. */ - int thisRegister = (++vPC)->u.operand; + int thisRegister = vPC[1].u.operand; JSValue thisVal = callFrame->r(thisRegister).jsValue(); if (thisVal.needsThisConversion()) callFrame->r(thisRegister) = JSValue(thisVal.toThisObject(callFrame)); - ++vPC; + vPC += OPCODE_LENGTH(op_convert_this); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_init_arguments) { @@ -3358,7 +3403,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi block. */ callFrame->r(RegisterFile::ArgumentsRegister) = JSValue(); - ++vPC; + vPC += OPCODE_LENGTH(op_init_arguments); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_create_arguments) { @@ -3374,7 +3419,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->setCalleeArguments(arguments); callFrame->r(RegisterFile::ArgumentsRegister) = JSValue(arguments); } - ++vPC; + vPC += OPCODE_LENGTH(op_create_arguments); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_construct) { @@ -3406,15 +3451,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (constructType == ConstructTypeJS) { ScopeChainNode* callDataScopeChain = constructData.js.scopeChain; - FunctionBodyNode* functionBodyNode = constructData.js.functionBody; - CodeBlock* newCodeBlock = &functionBodyNode->bytecode(callDataScopeChain); + CodeBlock* newCodeBlock = &constructData.js.functionExecutable->bytecode(callFrame, callDataScopeChain); Structure* structure; JSValue prototype = callFrame->r(proto).jsValue(); if (prototype.isObject()) structure = asObject(prototype)->inheritorID(); else - structure = callDataScopeChain->globalObject()->emptyObjectStructure(); + structure = callDataScopeChain->globalObject->emptyObjectStructure(); JSObject* newObject = new (globalData) JSObject(structure); callFrame->r(thisRegister) = JSValue(newObject); // "this" value @@ -3447,13 +3491,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi JSValue returnValue; { - SamplingTool::HostCallRecord callRecord(m_sampler); + SamplingTool::HostCallRecord callRecord(m_sampler.get()); returnValue = constructData.native.function(newCallFrame, asObject(v), args); } CHECK_FOR_EXCEPTION(); callFrame->r(dst) = JSValue(returnValue); - vPC += 7; + vPC += OPCODE_LENGTH(op_construct); NEXT_INSTRUCTION(); } @@ -3471,32 +3515,33 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi int dst = vPC[1].u.operand; if (LIKELY(callFrame->r(dst).jsValue().isObject())) { - vPC += 3; + vPC += OPCODE_LENGTH(op_construct_verify); NEXT_INSTRUCTION(); } int override = vPC[2].u.operand; callFrame->r(dst) = callFrame->r(override); - vPC += 3; + vPC += OPCODE_LENGTH(op_construct_verify); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_strcat) { - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; - int count = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; + int count = vPC[3].u.operand; - callFrame->r(dst) = concatenateStrings(callFrame, &callFrame->registers()[src], count); - ++vPC; + callFrame->r(dst) = jsString(callFrame, &callFrame->registers()[src], count); + CHECK_FOR_EXCEPTION(); + vPC += OPCODE_LENGTH(op_strcat); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_to_primitive) { - int dst = (++vPC)->u.operand; - int src = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int src = vPC[2].u.operand; callFrame->r(dst) = callFrame->r(src).jsValue().toPrimitive(callFrame); - ++vPC; + vPC += OPCODE_LENGTH(op_to_primitive); NEXT_INSTRUCTION(); } @@ -3507,7 +3552,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi of the current scope chain. The contents of the register scope are replaced by the result of toObject conversion of the scope. */ - int scope = (++vPC)->u.operand; + int scope = vPC[1].u.operand; JSValue v = callFrame->r(scope).jsValue(); JSObject* o = v.toObject(callFrame); CHECK_FOR_EXCEPTION(); @@ -3515,7 +3560,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi callFrame->r(scope) = JSValue(o); callFrame->setScopeChain(callFrame->scopeChain()->push(o)); - ++vPC; + vPC += OPCODE_LENGTH(op_push_scope); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_pop_scope) { @@ -3525,47 +3570,69 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi */ callFrame->setScopeChain(callFrame->scopeChain()->pop()); - ++vPC; + vPC += OPCODE_LENGTH(op_pop_scope); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_get_pnames) { - /* get_pnames dst(r) base(r) + /* get_pnames dst(r) base(r) i(n) size(n) breakTarget(offset) Creates a property name list for register base and puts it - in register dst. This is not a true JavaScript value, just - a synthetic value used to keep the iteration state in a - register. + in register dst, initializing i and size for iteration. If + base is undefined or null, jumps to breakTarget. */ - int dst = (++vPC)->u.operand; - int base = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int base = vPC[2].u.operand; + int i = vPC[3].u.operand; + int size = vPC[4].u.operand; + int breakTarget = vPC[5].u.operand; + + JSValue v = callFrame->r(base).jsValue(); + if (v.isUndefinedOrNull()) { + vPC += breakTarget; + NEXT_INSTRUCTION(); + } - callFrame->r(dst) = JSPropertyNameIterator::create(callFrame, callFrame->r(base).jsValue()); - ++vPC; + JSObject* o = v.toObject(callFrame); + Structure* structure = o->structure(); + JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache(); + if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame)) + jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o); + + callFrame->r(dst) = jsPropertyNameIterator; + callFrame->r(base) = JSValue(o); + callFrame->r(i) = Register::withInt(0); + callFrame->r(size) = Register::withInt(jsPropertyNameIterator->size()); + vPC += OPCODE_LENGTH(op_get_pnames); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_next_pname) { - /* next_pname dst(r) iter(r) target(offset) + /* next_pname dst(r) base(r) i(n) size(n) iter(r) target(offset) - Tries to copies the next name from property name list in - register iter. If there are names left, then copies one to - register dst, and jumps to offset target. If there are none - left, invalidates the iterator and continues to the next + Copies the next name from the property name list in + register iter to dst, then jumps to offset target. If there are no + names left, invalidates the iterator and continues to the next instruction. */ - int dst = (++vPC)->u.operand; - int iter = (++vPC)->u.operand; - int target = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int base = vPC[2].u.operand; + int i = vPC[3].u.operand; + int size = vPC[4].u.operand; + int iter = vPC[5].u.operand; + int target = vPC[6].u.operand; JSPropertyNameIterator* it = callFrame->r(iter).propertyNameIterator(); - if (JSValue temp = it->next(callFrame)) { - CHECK_FOR_TIMEOUT(); - callFrame->r(dst) = JSValue(temp); - vPC += target; - NEXT_INSTRUCTION(); + while (callFrame->r(i).i() != callFrame->r(size).i()) { + JSValue key = it->get(callFrame, asObject(callFrame->r(base).jsValue()), callFrame->r(i).i()); + callFrame->r(i) = Register::withInt(callFrame->r(i).i() + 1); + if (key) { + CHECK_FOR_TIMEOUT(); + callFrame->r(dst) = key; + vPC += target; + NEXT_INSTRUCTION(); + } } - it->invalidate(); - ++vPC; + vPC += OPCODE_LENGTH(op_next_pname); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_jmp_scopes) { @@ -3575,8 +3642,8 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi specified by immediate number count, then jumps to offset target. */ - int count = (++vPC)->u.operand; - int target = (++vPC)->u.operand; + int count = vPC[1].u.operand; + int target = vPC[2].u.operand; ScopeChainNode* tmp = callFrame->scopeChain(); while (count--) @@ -3599,7 +3666,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi */ callFrame->setScopeChain(createExceptionScope(callFrame, vPC)); - vPC += 4; + vPC += OPCODE_LENGTH(op_push_new_scope); NEXT_INSTRUCTION(); } #if HAVE(COMPUTED_GOTO) @@ -3614,11 +3681,11 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi */ ASSERT(exceptionValue); ASSERT(!globalData->exception); - int ex = (++vPC)->u.operand; + int ex = vPC[1].u.operand; callFrame->r(ex) = exceptionValue; exceptionValue = JSValue(); - ++vPC; + vPC += OPCODE_LENGTH(op_catch); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_throw) { @@ -3632,7 +3699,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi else the script returns control to the nearest native caller. */ - int ex = (++vPC)->u.operand; + int ex = vPC[1].u.operand; exceptionValue = callFrame->r(ex).jsValue(); handler = throwException(callFrame, exceptionValue, vPC - callFrame->codeBlock()->instructions().begin(), true); @@ -3652,14 +3719,14 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi constant message as the message string. The result is written to register dst. */ - int dst = (++vPC)->u.operand; - int type = (++vPC)->u.operand; - int message = (++vPC)->u.operand; + int dst = vPC[1].u.operand; + int type = vPC[2].u.operand; + int message = vPC[3].u.operand; CodeBlock* codeBlock = callFrame->codeBlock(); - callFrame->r(dst) = JSValue(Error::create(callFrame, (ErrorType)type, callFrame->r(message).jsValue().toString(callFrame), codeBlock->lineNumberForBytecodeOffset(callFrame, vPC - codeBlock->instructions().begin()), codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL())); + callFrame->r(dst) = JSValue(Error::create(callFrame, (ErrorType)type, callFrame->r(message).jsValue().toString(callFrame), codeBlock->lineNumberForBytecodeOffset(callFrame, vPC - codeBlock->instructions().begin()), codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL())); - ++vPC; + vPC += OPCODE_LENGTH(op_new_error); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_end) { @@ -3674,7 +3741,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT(scopeChain->refCount > 1); scopeChain->deref(); } - int result = (++vPC)->u.operand; + int result = vPC[1].u.operand; return callFrame->r(result).jsValue(); } DEFINE_OPCODE(op_put_getter) { @@ -3688,9 +3755,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Unlike many opcodes, this one does not write any output to the register file. */ - int base = (++vPC)->u.operand; - int property = (++vPC)->u.operand; - int function = (++vPC)->u.operand; + int base = vPC[1].u.operand; + int property = vPC[2].u.operand; + int function = vPC[3].u.operand; ASSERT(callFrame->r(base).jsValue().isObject()); JSObject* baseObj = asObject(callFrame->r(base).jsValue()); @@ -3698,7 +3765,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi ASSERT(callFrame->r(function).jsValue().isObject()); baseObj->defineGetter(callFrame, ident, asObject(callFrame->r(function).jsValue())); - ++vPC; + vPC += OPCODE_LENGTH(op_put_getter); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_put_setter) { @@ -3712,17 +3779,17 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Unlike many opcodes, this one does not write any output to the register file. */ - int base = (++vPC)->u.operand; - int property = (++vPC)->u.operand; - int function = (++vPC)->u.operand; + int base = vPC[1].u.operand; + int property = vPC[2].u.operand; + int function = vPC[3].u.operand; ASSERT(callFrame->r(base).jsValue().isObject()); JSObject* baseObj = asObject(callFrame->r(base).jsValue()); Identifier& ident = callFrame->codeBlock()->identifier(property); ASSERT(callFrame->r(function).jsValue().isObject()); - baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue())); + baseObj->defineSetter(callFrame, ident, asObject(callFrame->r(function).jsValue()), 0); - ++vPC; + vPC += OPCODE_LENGTH(op_put_setter); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_method_check) { @@ -3735,9 +3802,9 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Places the address of the next instruction into the retAddrDst register and jumps to offset target from the current instruction. */ - int retAddrDst = (++vPC)->u.operand; - int target = (++vPC)->u.operand; - callFrame->r(retAddrDst) = vPC + 1; + int retAddrDst = vPC[1].u.operand; + int target = vPC[2].u.operand; + callFrame->r(retAddrDst) = vPC + OPCODE_LENGTH(op_jsr); vPC += target; NEXT_INSTRUCTION(); @@ -3749,7 +3816,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi differs from op_jmp because the target address is stored in a register, not as an immediate. */ - int retAddrSrc = (++vPC)->u.operand; + int retAddrSrc = vPC[1].u.operand; vPC = callFrame->r(retAddrSrc).vPC(); NEXT_INSTRUCTION(); } @@ -3759,13 +3826,13 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi Notifies the debugger of the current state of execution. This opcode is only generated while the debugger is attached. */ - int debugHookID = (++vPC)->u.operand; - int firstLine = (++vPC)->u.operand; - int lastLine = (++vPC)->u.operand; + int debugHookID = vPC[1].u.operand; + int firstLine = vPC[2].u.operand; + int lastLine = vPC[3].u.operand; debug(callFrame, static_cast<DebugHookID>(debugHookID), firstLine, lastLine); - ++vPC; + vPC += OPCODE_LENGTH(op_debug); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_profile_will_call) { @@ -3779,7 +3846,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (*enabledProfilerReference) (*enabledProfilerReference)->willExecute(callFrame, callFrame->r(function).jsValue()); - vPC += 2; + vPC += OPCODE_LENGTH(op_profile_will_call); NEXT_INSTRUCTION(); } DEFINE_OPCODE(op_profile_did_call) { @@ -3793,7 +3860,7 @@ JSValue Interpreter::privateExecute(ExecutionFlag flag, RegisterFile* registerFi if (*enabledProfilerReference) (*enabledProfilerReference)->didExecute(callFrame, callFrame->r(function).jsValue()); - vPC += 2; + vPC += OPCODE_LENGTH(op_profile_did_call); NEXT_INSTRUCTION(); } vm_throw: { @@ -3832,7 +3899,7 @@ JSValue Interpreter::retrieveArguments(CallFrame* callFrame, JSFunction* functio CodeBlock* codeBlock = functionCallFrame->codeBlock(); if (codeBlock->usesArguments()) { ASSERT(codeBlock->codeType() == FunctionCode); - SymbolTable& symbolTable = codeBlock->symbolTable(); + SymbolTable& symbolTable = *codeBlock->symbolTable(); int argumentsIndex = symbolTable.get(functionCallFrame->propertyNames().arguments.ustring().rep()).getIndex(); if (!functionCallFrame->r(argumentsIndex).jsValue()) { Arguments* arguments = new (callFrame) Arguments(functionCallFrame); @@ -3885,8 +3952,8 @@ void Interpreter::retrieveLastCaller(CallFrame* callFrame, int& lineNumber, intp unsigned bytecodeOffset = bytecodeOffsetForPC(callerFrame, callerCodeBlock, callFrame->returnPC()); lineNumber = callerCodeBlock->lineNumberForBytecodeOffset(callerFrame, bytecodeOffset - 1); - sourceID = callerCodeBlock->ownerNode()->sourceID(); - sourceURL = callerCodeBlock->ownerNode()->sourceURL(); + sourceID = callerCodeBlock->ownerExecutable()->sourceID(); + sourceURL = callerCodeBlock->ownerExecutable()->sourceURL(); function = callerFrame->callee(); } @@ -3899,4 +3966,40 @@ CallFrame* Interpreter::findFunctionCallFrame(CallFrame* callFrame, InternalFunc return 0; } +void Interpreter::enableSampler() +{ +#if ENABLE(OPCODE_SAMPLING) + if (!m_sampler) { + m_sampler.set(new SamplingTool(this)); + m_sampler->setup(); + } +#endif +} +void Interpreter::dumpSampleData(ExecState* exec) +{ +#if ENABLE(OPCODE_SAMPLING) + if (m_sampler) + m_sampler->dump(exec); +#else + UNUSED_PARAM(exec); +#endif +} +void Interpreter::startSampling() +{ +#if ENABLE(SAMPLING_THREAD) + if (!m_sampleEntryDepth) + SamplingThread::start(); + + m_sampleEntryDepth++; +#endif +} +void Interpreter::stopSampling() +{ +#if ENABLE(SAMPLING_THREAD) + m_sampleEntryDepth--; + if (!m_sampleEntryDepth) + SamplingThread::stop(); +#endif +} + } // namespace JSC diff --git a/JavaScriptCore/interpreter/Interpreter.h b/JavaScriptCore/interpreter/Interpreter.h index 519c508..e17b055 100644 --- a/JavaScriptCore/interpreter/Interpreter.h +++ b/JavaScriptCore/interpreter/Interpreter.h @@ -42,12 +42,12 @@ namespace JSC { class CodeBlock; - class EvalNode; - class FunctionBodyNode; + class EvalExecutable; + class FunctionExecutable; class InternalFunction; class JSFunction; class JSGlobalObject; - class ProgramNode; + class ProgramExecutable; class Register; class ScopeChainNode; class SamplingTool; @@ -95,9 +95,9 @@ namespace JSC { bool isOpcode(Opcode); - JSValue execute(ProgramNode*, CallFrame*, ScopeChainNode*, JSObject* thisObj, JSValue* exception); - JSValue execute(FunctionBodyNode*, CallFrame*, JSFunction*, JSObject* thisObj, const ArgList& args, ScopeChainNode*, JSValue* exception); - JSValue execute(EvalNode* evalNode, CallFrame* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception); + JSValue execute(ProgramExecutable*, CallFrame*, ScopeChainNode*, JSObject* thisObj, JSValue* exception); + JSValue execute(FunctionExecutable*, CallFrame*, JSFunction*, JSObject* thisObj, const ArgList& args, ScopeChainNode*, JSValue* exception); + JSValue execute(EvalExecutable* evalNode, CallFrame* exec, JSObject* thisObj, ScopeChainNode* scopeChain, JSValue* exception); JSValue retrieveArguments(CallFrame*, JSFunction*) const; JSValue retrieveCaller(CallFrame*, InternalFunction*) const; @@ -105,21 +105,23 @@ namespace JSC { void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc); - void setSampler(SamplingTool* sampler) { m_sampler = sampler; } - SamplingTool* sampler() { return m_sampler; } + SamplingTool* sampler() { return m_sampler.get(); } NEVER_INLINE JSValue callEval(CallFrame*, RegisterFile*, Register* argv, int argc, int registerOffset, JSValue& exceptionValue); NEVER_INLINE HandlerInfo* throwException(CallFrame*&, JSValue&, unsigned bytecodeOffset, bool); NEVER_INLINE void debug(CallFrame*, DebugHookID, int firstLine, int lastLine); + void dumpSampleData(ExecState* exec); + void startSampling(); + void stopSampling(); private: enum ExecutionFlag { Normal, InitializeAndReturn }; - CallFrameClosure prepareForRepeatCall(FunctionBodyNode*, CallFrame*, JSFunction*, int argCount, ScopeChainNode*, JSValue* exception); + CallFrameClosure prepareForRepeatCall(FunctionExecutable*, CallFrame*, JSFunction*, int argCount, ScopeChainNode*, JSValue* exception); void endRepeatCall(CallFrameClosure&); JSValue execute(CallFrameClosure&, JSValue* exception); - JSValue execute(EvalNode*, CallFrame*, JSObject* thisObject, int globalRegisterOffset, ScopeChainNode*, JSValue* exception); + JSValue execute(EvalExecutable*, CallFrame*, JSObject* thisObject, int globalRegisterOffset, ScopeChainNode*, JSValue* exception); #if USE(INTERPRETER) NEVER_INLINE bool resolve(CallFrame*, Instruction*, JSValue& exceptionValue); @@ -127,7 +129,6 @@ namespace JSC { NEVER_INLINE bool resolveGlobal(CallFrame*, Instruction*, JSValue& exceptionValue); NEVER_INLINE void resolveBase(CallFrame*, Instruction* vPC); NEVER_INLINE bool resolveBaseAndProperty(CallFrame*, Instruction*, JSValue& exceptionValue); - NEVER_INLINE bool resolveBaseAndFunc(CallFrame*, Instruction*, JSValue& exceptionValue); NEVER_INLINE ScopeChainNode* createExceptionScope(CallFrame*, const Instruction* vPC); void tryCacheGetByID(CallFrame*, CodeBlock*, Instruction*, JSValue baseValue, const Identifier& propertyName, const PropertySlot&); @@ -149,7 +150,9 @@ namespace JSC { bool isCallBytecode(Opcode opcode) { return opcode == getOpcode(op_call) || opcode == getOpcode(op_construct) || opcode == getOpcode(op_call_eval); } - SamplingTool* m_sampler; + void enableSampler(); + int m_sampleEntryDepth; + OwnPtr<SamplingTool> m_sampler; int m_reentryDepth; diff --git a/JavaScriptCore/interpreter/Register.h b/JavaScriptCore/interpreter/Register.h index 95ae5f6..d0b0568 100644 --- a/JavaScriptCore/interpreter/Register.h +++ b/JavaScriptCore/interpreter/Register.h @@ -54,9 +54,6 @@ namespace JSC { Register(JSValue); JSValue jsValue() const; - - bool marked() const; - void markChildren(MarkStack&); Register(JSActivation*); Register(CallFrame*); @@ -107,6 +104,9 @@ namespace JSC { ALWAYS_INLINE Register::Register(JSValue v) { +#if ENABLE(JSC_ZOMBIES) + ASSERT(!v.isZombie()); +#endif u.value = JSValue::encode(v); } @@ -114,11 +114,6 @@ namespace JSC { { return JSValue::decode(u.value); } - - ALWAYS_INLINE bool Register::marked() const - { - return jsValue().marked(); - } // Interpreter functions diff --git a/JavaScriptCore/interpreter/RegisterFile.cpp b/JavaScriptCore/interpreter/RegisterFile.cpp index cfcf1d3..5424199 100644 --- a/JavaScriptCore/interpreter/RegisterFile.cpp +++ b/JavaScriptCore/interpreter/RegisterFile.cpp @@ -36,9 +36,12 @@ RegisterFile::~RegisterFile() #if HAVE(MMAP) munmap(m_buffer, ((m_max - m_start) + m_maxGlobals) * sizeof(Register)); #elif HAVE(VIRTUALALLOC) +#if PLATFORM(WINCE) + VirtualFree(m_buffer, DWORD(m_commitEnd) - DWORD(m_buffer), MEM_DECOMMIT); +#endif VirtualFree(m_buffer, 0, MEM_RELEASE); #else - #error "Don't know how to release virtual memory on this platform." + fastFree(m_buffer); #endif } diff --git a/JavaScriptCore/interpreter/RegisterFile.h b/JavaScriptCore/interpreter/RegisterFile.h index b5f7452..953c70f 100644 --- a/JavaScriptCore/interpreter/RegisterFile.h +++ b/JavaScriptCore/interpreter/RegisterFile.h @@ -204,8 +204,16 @@ namespace JSC { CRASH(); } m_commitEnd = reinterpret_cast<Register*>(reinterpret_cast<char*>(m_buffer) + committedSize); - #else - #error "Don't know how to reserve virtual memory on this platform." + #else + /* + * If neither MMAP nor VIRTUALALLOC are available - use fastMalloc instead. + * + * Please note that this is the fallback case, which is non-optimal. + * If any possible, the platform should provide for a better memory + * allocation mechanism that allows for "lazy commit" or dynamic + * pre-allocation, similar to mmap or VirtualAlloc, to avoid waste of memory. + */ + m_buffer = static_cast<Register*>(fastMalloc(bufferLength)); #endif m_start = m_buffer + maxGlobals; m_end = m_start; diff --git a/JavaScriptCore/jit/ExecutableAllocator.h b/JavaScriptCore/jit/ExecutableAllocator.h index 4ed47e3..9ca62c8 100644 --- a/JavaScriptCore/jit/ExecutableAllocator.h +++ b/JavaScriptCore/jit/ExecutableAllocator.h @@ -38,6 +38,10 @@ #include <sys/mman.h> #endif +#if PLATFORM(SYMBIAN) +#include <e32std.h> +#endif + #define JIT_ALLOCATOR_PAGE_SIZE (ExecutableAllocator::pageSize) #define JIT_ALLOCATOR_LARGE_ALLOC_SIZE (ExecutableAllocator::pageSize * 4) @@ -74,6 +78,9 @@ private: struct Allocation { char* pages; size_t size; +#if PLATFORM(SYMBIAN) + RChunk* chunk; +#endif }; typedef Vector<Allocation, 2> AllocationList; @@ -176,30 +183,51 @@ public: static void cacheFlush(void*, size_t) { } -#elif PLATFORM_ARM_ARCH(7) && PLATFORM(IPHONE) +#elif PLATFORM(ARM_THUMB2) && PLATFORM(IPHONE) static void cacheFlush(void* code, size_t size) { sys_dcache_flush(code, size); sys_icache_invalidate(code, size); } -#elif PLATFORM(ARM) +#elif PLATFORM(ARM_THUMB2) && PLATFORM(LINUX) + static void cacheFlush(void* code, size_t size) + { + asm volatile ( + "push {r7}\n" + "mov r0, %0\n" + "mov r1, %1\n" + "movw r7, #0x2\n" + "movt r7, #0xf\n" + "movs r2, #0x0\n" + "svc 0x0\n" + "pop {r7}\n" + : + : "r" (code), "r" (reinterpret_cast<char*>(code) + size) + : "r0", "r1", "r2"); + } +#elif PLATFORM(SYMBIAN) static void cacheFlush(void* code, size_t size) { - #if COMPILER(GCC) && (GCC_VERSION >= 30406) - __clear_cache(reinterpret_cast<char*>(code), reinterpret_cast<char*>(code) + size); - #else - const int syscall = 0xf0002; - __asm __volatile ( - "mov r0, %0\n" - "mov r1, %1\n" - "mov r7, %2\n" - "mov r2, #0x0\n" - "swi 0x00000000\n" - : - : "r" (code), "r" (reinterpret_cast<char*>(code) + size), "r" (syscall) - : "r0", "r1", "r7"); - #endif // COMPILER(GCC) && (GCC_VERSION >= 30406) + User::IMB_Range(code, static_cast<char*>(code) + size); } +#elif PLATFORM(ARM_TRADITIONAL) && PLATFORM(LINUX) + static void cacheFlush(void* code, size_t size) + { + asm volatile ( + "push {r7}\n" + "mov r0, %0\n" + "mov r1, %1\n" + "mov r7, #0xf0000\n" + "add r7, r7, #0x2\n" + "mov r2, #0x0\n" + "svc 0x0\n" + "pop {r7}\n" + : + : "r" (code), "r" (reinterpret_cast<char*>(code) + size) + : "r0", "r1", "r2"); + } +#else + #error "The cacheFlush support is missing on this platform." #endif private: diff --git a/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp b/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp index 4bd5a2c..13a8626 100644 --- a/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp +++ b/JavaScriptCore/jit/ExecutableAllocatorPosix.cpp @@ -44,7 +44,10 @@ void ExecutableAllocator::intializePageSize() ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n) { - ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0)), n }; + void* allocation = mmap(NULL, n, INITIAL_PROTECTION_FLAGS, MAP_PRIVATE | MAP_ANON, VM_TAG_FOR_EXECUTABLEALLOCATOR_MEMORY, 0); + if (allocation == MAP_FAILED) + CRASH(); + ExecutablePool::Allocation alloc = { reinterpret_cast<char*>(allocation), n }; return alloc; } diff --git a/JavaScriptCore/jit/ExecutableAllocatorSymbian.cpp b/JavaScriptCore/jit/ExecutableAllocatorSymbian.cpp new file mode 100644 index 0000000..c96ecae --- /dev/null +++ b/JavaScriptCore/jit/ExecutableAllocatorSymbian.cpp @@ -0,0 +1,75 @@ +/* + * Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + * + * 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 "ExecutableAllocator.h" + +#if ENABLE(ASSEMBLER) && PLATFORM(SYMBIAN) + +#include <e32hal.h> +#include <e32std.h> + +// Set the page size to 256 Kb to compensate for moving memory model limitation +const size_t MOVING_MEM_PAGE_SIZE = 256 * 1024; + +namespace JSC { + +void ExecutableAllocator::intializePageSize() +{ +#if PLATFORM_ARM_ARCH(5) + // The moving memory model (as used in ARMv5 and earlier platforms) + // on Symbian OS limits the number of chunks for each process to 16. + // To mitigate this limitation increase the pagesize to + // allocate less of larger chunks. + ExecutableAllocator::pageSize = MOVING_MEM_PAGE_SIZE; +#else + TInt page_size; + UserHal::PageSizeInBytes(page_size); + ExecutableAllocator::pageSize = page_size; +#endif +} + +ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n) +{ + RChunk* codeChunk = new RChunk(); + + TInt errorCode = codeChunk->CreateLocalCode(n, n); + + char* allocation = reinterpret_cast<char*>(codeChunk->Base()); + if (!allocation) + CRASH(); + ExecutablePool::Allocation alloc = { allocation, n, codeChunk }; + return alloc; +} + +void ExecutablePool::systemRelease(const ExecutablePool::Allocation& alloc) +{ + alloc.chunk->Close(); + delete alloc.chunk; +} + +#if ENABLE(ASSEMBLER_WX_EXCLUSIVE) +#error "ASSEMBLER_WX_EXCLUSIVE not yet suported on this platform." +#endif + +} + +#endif // HAVE(ASSEMBLER) diff --git a/JavaScriptCore/jit/ExecutableAllocatorWin.cpp b/JavaScriptCore/jit/ExecutableAllocatorWin.cpp index a9ba7d0..e6ac855 100644 --- a/JavaScriptCore/jit/ExecutableAllocatorWin.cpp +++ b/JavaScriptCore/jit/ExecutableAllocatorWin.cpp @@ -42,7 +42,10 @@ void ExecutableAllocator::intializePageSize() ExecutablePool::Allocation ExecutablePool::systemAlloc(size_t n) { - ExecutablePool::Allocation alloc = {reinterpret_cast<char*>(VirtualAlloc(0, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE)), n}; + void* allocation = VirtualAlloc(0, n, MEM_COMMIT | MEM_RESERVE, PAGE_EXECUTE_READWRITE); + if (!allocation) + CRASH(); + ExecutablePool::Allocation alloc = {reinterpret_cast<char*>(allocation), n}; return alloc; } diff --git a/JavaScriptCore/jit/JIT.cpp b/JavaScriptCore/jit/JIT.cpp index 0d6d1b8..585486f 100644 --- a/JavaScriptCore/jit/JIT.cpp +++ b/JavaScriptCore/jit/JIT.cpp @@ -37,7 +37,6 @@ JSC::MacroAssemblerX86Common::SSE2CheckState JSC::MacroAssemblerX86Common::s_sse #include "CodeBlock.h" #include "Interpreter.h" #include "JITInlineMethods.h" -#include "JITStubs.h" #include "JITStubCall.h" #include "JSArray.h" #include "JSFunction.h" @@ -195,14 +194,13 @@ void JIT::privateCompileMainPass() switch (m_interpreter->getOpcodeID(currentInstruction->u.opcode)) { DEFINE_BINARY_OP(op_del_by_val) -#if !USE(JSVALUE32_64) +#if USE(JSVALUE32) DEFINE_BINARY_OP(op_div) #endif DEFINE_BINARY_OP(op_in) DEFINE_BINARY_OP(op_less) DEFINE_BINARY_OP(op_lesseq) DEFINE_BINARY_OP(op_urshift) - DEFINE_UNARY_OP(op_get_pnames) DEFINE_UNARY_OP(op_is_boolean) DEFINE_UNARY_OP(op_is_function) DEFINE_UNARY_OP(op_is_number) @@ -230,7 +228,7 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_create_arguments) DEFINE_OP(op_debug) DEFINE_OP(op_del_by_id) -#if USE(JSVALUE32_64) +#if !USE(JSVALUE32) DEFINE_OP(op_div) #endif DEFINE_OP(op_end) @@ -240,7 +238,9 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_eq_null) DEFINE_OP(op_get_by_id) DEFINE_OP(op_get_by_val) + DEFINE_OP(op_get_by_pname) DEFINE_OP(op_get_global_var) + DEFINE_OP(op_get_pnames) DEFINE_OP(op_get_scoped_var) DEFINE_OP(op_instanceof) DEFINE_OP(op_jeq_null) @@ -250,6 +250,7 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_jneq_null) DEFINE_OP(op_jneq_ptr) DEFINE_OP(op_jnless) + DEFINE_OP(op_jless) DEFINE_OP(op_jnlesseq) DEFINE_OP(op_jsr) DEFINE_OP(op_jtrue) @@ -258,6 +259,7 @@ void JIT::privateCompileMainPass() DEFINE_OP(op_loop_if_less) DEFINE_OP(op_loop_if_lesseq) DEFINE_OP(op_loop_if_true) + DEFINE_OP(op_loop_if_false) DEFINE_OP(op_lshift) DEFINE_OP(op_method_check) DEFINE_OP(op_mod) @@ -379,20 +381,23 @@ void JIT::privateCompileSlowCases() DEFINE_SLOWCASE_OP(op_construct) DEFINE_SLOWCASE_OP(op_construct_verify) DEFINE_SLOWCASE_OP(op_convert_this) -#if USE(JSVALUE32_64) +#if !USE(JSVALUE32) DEFINE_SLOWCASE_OP(op_div) #endif DEFINE_SLOWCASE_OP(op_eq) DEFINE_SLOWCASE_OP(op_get_by_id) DEFINE_SLOWCASE_OP(op_get_by_val) + DEFINE_SLOWCASE_OP(op_get_by_pname) DEFINE_SLOWCASE_OP(op_instanceof) DEFINE_SLOWCASE_OP(op_jfalse) DEFINE_SLOWCASE_OP(op_jnless) + DEFINE_SLOWCASE_OP(op_jless) DEFINE_SLOWCASE_OP(op_jnlesseq) DEFINE_SLOWCASE_OP(op_jtrue) DEFINE_SLOWCASE_OP(op_loop_if_less) DEFINE_SLOWCASE_OP(op_loop_if_lesseq) DEFINE_SLOWCASE_OP(op_loop_if_true) + DEFINE_SLOWCASE_OP(op_loop_if_false) DEFINE_SLOWCASE_OP(op_lshift) DEFINE_SLOWCASE_OP(op_method_check) DEFINE_SLOWCASE_OP(op_mod) @@ -438,7 +443,7 @@ void JIT::privateCompileSlowCases() #endif } -void JIT::privateCompile() +JITCode JIT::privateCompile() { sampleCodeBlock(m_codeBlock); #if ENABLE(OPCODE_SAMPLING) @@ -489,21 +494,21 @@ void JIT::privateCompile() ASSERT(record.type == SwitchRecord::Immediate || record.type == SwitchRecord::Character); ASSERT(record.jumpTable.simpleJumpTable->branchOffsets.size() == record.jumpTable.simpleJumpTable->ctiOffsets.size()); - record.jumpTable.simpleJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeIndex + 3 + record.defaultOffset]); + record.jumpTable.simpleJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeIndex + record.defaultOffset]); for (unsigned j = 0; j < record.jumpTable.simpleJumpTable->branchOffsets.size(); ++j) { unsigned offset = record.jumpTable.simpleJumpTable->branchOffsets[j]; - record.jumpTable.simpleJumpTable->ctiOffsets[j] = offset ? patchBuffer.locationOf(m_labels[bytecodeIndex + 3 + offset]) : record.jumpTable.simpleJumpTable->ctiDefault; + record.jumpTable.simpleJumpTable->ctiOffsets[j] = offset ? patchBuffer.locationOf(m_labels[bytecodeIndex + offset]) : record.jumpTable.simpleJumpTable->ctiDefault; } } else { ASSERT(record.type == SwitchRecord::String); - record.jumpTable.stringJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeIndex + 3 + record.defaultOffset]); + record.jumpTable.stringJumpTable->ctiDefault = patchBuffer.locationOf(m_labels[bytecodeIndex + record.defaultOffset]); StringJumpTable::StringOffsetTable::iterator end = record.jumpTable.stringJumpTable->offsetTable.end(); for (StringJumpTable::StringOffsetTable::iterator it = record.jumpTable.stringJumpTable->offsetTable.begin(); it != end; ++it) { unsigned offset = it->second.branchOffset; - it->second.ctiOffset = offset ? patchBuffer.locationOf(m_labels[bytecodeIndex + 3 + offset]) : record.jumpTable.stringJumpTable->ctiDefault; + it->second.ctiOffset = offset ? patchBuffer.locationOf(m_labels[bytecodeIndex + offset]) : record.jumpTable.stringJumpTable->ctiDefault; } } } @@ -552,7 +557,7 @@ void JIT::privateCompile() info.callReturnLocation = m_codeBlock->structureStubInfo(m_methodCallCompilationInfo[i].propertyAccessIndex).callReturnLocation; } - m_codeBlock->setJITCode(patchBuffer.finalizeCode()); + return patchBuffer.finalizeCode(); } #if !USE(JSVALUE32_64) @@ -587,12 +592,11 @@ void JIT::unlinkCall(CallLinkInfo* callLinkInfo) void JIT::linkCall(JSFunction* callee, CodeBlock* callerCodeBlock, CodeBlock* calleeCodeBlock, JITCode& code, CallLinkInfo* callLinkInfo, int callerArgCount, JSGlobalData* globalData) { - ASSERT(calleeCodeBlock); RepatchBuffer repatchBuffer(callerCodeBlock); // Currently we only link calls with the exact number of arguments. // If this is a native call calleeCodeBlock is null so the number of parameters is unimportant - if (callerArgCount == calleeCodeBlock->m_numParameters || calleeCodeBlock->codeType() == NativeCode) { + if (!calleeCodeBlock || (callerArgCount == calleeCodeBlock->m_numParameters)) { ASSERT(!callLinkInfo->isLinked()); if (calleeCodeBlock) diff --git a/JavaScriptCore/jit/JIT.h b/JavaScriptCore/jit/JIT.h index 93f47d9..0b902b9 100644 --- a/JavaScriptCore/jit/JIT.h +++ b/JavaScriptCore/jit/JIT.h @@ -38,6 +38,8 @@ #define JIT_CLASS_ALIGNMENT #endif +#define ASSERT_JIT_OFFSET(actual, expected) ASSERT_WITH_MESSAGE(actual == expected, "JIT Offset \"%s\" should be %d, not %d.\n", #expected, static_cast<int>(actual), static_cast<int>(expected)); + #include "CodeBlock.h" #include "Interpreter.h" #include "JITCode.h" @@ -191,82 +193,81 @@ namespace JSC { // MacroAssembler will need to plant register swaps if it is not - // however the code will still function correctly. #if PLATFORM(X86_64) - static const RegisterID returnValueRegister = X86::eax; - static const RegisterID cachedResultRegister = X86::eax; - static const RegisterID firstArgumentRegister = X86::edi; - - static const RegisterID timeoutCheckRegister = X86::r12; - static const RegisterID callFrameRegister = X86::r13; - static const RegisterID tagTypeNumberRegister = X86::r14; - static const RegisterID tagMaskRegister = X86::r15; - - static const RegisterID regT0 = X86::eax; - static const RegisterID regT1 = X86::edx; - static const RegisterID regT2 = X86::ecx; - static const RegisterID regT3 = X86::ebx; - - static const FPRegisterID fpRegT0 = X86::xmm0; - static const FPRegisterID fpRegT1 = X86::xmm1; - static const FPRegisterID fpRegT2 = X86::xmm2; + static const RegisterID returnValueRegister = X86Registers::eax; + static const RegisterID cachedResultRegister = X86Registers::eax; + static const RegisterID firstArgumentRegister = X86Registers::edi; + + static const RegisterID timeoutCheckRegister = X86Registers::r12; + static const RegisterID callFrameRegister = X86Registers::r13; + static const RegisterID tagTypeNumberRegister = X86Registers::r14; + static const RegisterID tagMaskRegister = X86Registers::r15; + + static const RegisterID regT0 = X86Registers::eax; + static const RegisterID regT1 = X86Registers::edx; + static const RegisterID regT2 = X86Registers::ecx; + static const RegisterID regT3 = X86Registers::ebx; + + static const FPRegisterID fpRegT0 = X86Registers::xmm0; + static const FPRegisterID fpRegT1 = X86Registers::xmm1; + static const FPRegisterID fpRegT2 = X86Registers::xmm2; #elif PLATFORM(X86) - static const RegisterID returnValueRegister = X86::eax; - static const RegisterID cachedResultRegister = X86::eax; + static const RegisterID returnValueRegister = X86Registers::eax; + static const RegisterID cachedResultRegister = X86Registers::eax; // On x86 we always use fastcall conventions = but on // OS X if might make more sense to just use regparm. - static const RegisterID firstArgumentRegister = X86::ecx; - - static const RegisterID timeoutCheckRegister = X86::esi; - static const RegisterID callFrameRegister = X86::edi; - - static const RegisterID regT0 = X86::eax; - static const RegisterID regT1 = X86::edx; - static const RegisterID regT2 = X86::ecx; - static const RegisterID regT3 = X86::ebx; - - static const FPRegisterID fpRegT0 = X86::xmm0; - static const FPRegisterID fpRegT1 = X86::xmm1; - static const FPRegisterID fpRegT2 = X86::xmm2; -#elif PLATFORM_ARM_ARCH(7) - static const RegisterID returnValueRegister = ARM::r0; - static const RegisterID cachedResultRegister = ARM::r0; - static const RegisterID firstArgumentRegister = ARM::r0; - - static const RegisterID regT0 = ARM::r0; - static const RegisterID regT1 = ARM::r1; - static const RegisterID regT2 = ARM::r2; - static const RegisterID regT3 = ARM::r4; - - static const RegisterID callFrameRegister = ARM::r5; - static const RegisterID timeoutCheckRegister = ARM::r6; - - static const FPRegisterID fpRegT0 = ARM::d0; - static const FPRegisterID fpRegT1 = ARM::d1; - static const FPRegisterID fpRegT2 = ARM::d2; -#elif PLATFORM(ARM) - static const RegisterID returnValueRegister = ARM::r0; - static const RegisterID cachedResultRegister = ARM::r0; - static const RegisterID firstArgumentRegister = ARM::r0; - - static const RegisterID timeoutCheckRegister = ARM::r5; - static const RegisterID callFrameRegister = ARM::r4; - static const RegisterID ctiReturnRegister = ARM::r6; - - static const RegisterID regT0 = ARM::r0; - static const RegisterID regT1 = ARM::r1; - static const RegisterID regT2 = ARM::r2; + static const RegisterID firstArgumentRegister = X86Registers::ecx; + + static const RegisterID timeoutCheckRegister = X86Registers::esi; + static const RegisterID callFrameRegister = X86Registers::edi; + + static const RegisterID regT0 = X86Registers::eax; + static const RegisterID regT1 = X86Registers::edx; + static const RegisterID regT2 = X86Registers::ecx; + static const RegisterID regT3 = X86Registers::ebx; + + static const FPRegisterID fpRegT0 = X86Registers::xmm0; + static const FPRegisterID fpRegT1 = X86Registers::xmm1; + static const FPRegisterID fpRegT2 = X86Registers::xmm2; +#elif PLATFORM(ARM_THUMB2) + static const RegisterID returnValueRegister = ARMRegisters::r0; + static const RegisterID cachedResultRegister = ARMRegisters::r0; + static const RegisterID firstArgumentRegister = ARMRegisters::r0; + + static const RegisterID regT0 = ARMRegisters::r0; + static const RegisterID regT1 = ARMRegisters::r1; + static const RegisterID regT2 = ARMRegisters::r2; + static const RegisterID regT3 = ARMRegisters::r4; + + static const RegisterID callFrameRegister = ARMRegisters::r5; + static const RegisterID timeoutCheckRegister = ARMRegisters::r6; + + static const FPRegisterID fpRegT0 = ARMRegisters::d0; + static const FPRegisterID fpRegT1 = ARMRegisters::d1; + static const FPRegisterID fpRegT2 = ARMRegisters::d2; +#elif PLATFORM(ARM_TRADITIONAL) + static const RegisterID returnValueRegister = ARMRegisters::r0; + static const RegisterID cachedResultRegister = ARMRegisters::r0; + static const RegisterID firstArgumentRegister = ARMRegisters::r0; + + static const RegisterID timeoutCheckRegister = ARMRegisters::r5; + static const RegisterID callFrameRegister = ARMRegisters::r4; + + static const RegisterID regT0 = ARMRegisters::r0; + static const RegisterID regT1 = ARMRegisters::r1; + static const RegisterID regT2 = ARMRegisters::r2; // Callee preserved - static const RegisterID regT3 = ARM::r7; + static const RegisterID regT3 = ARMRegisters::r7; - static const RegisterID regS0 = ARM::S0; + static const RegisterID regS0 = ARMRegisters::S0; // Callee preserved - static const RegisterID regS1 = ARM::S1; + static const RegisterID regS1 = ARMRegisters::S1; - static const RegisterID regStackPtr = ARM::sp; - static const RegisterID regLink = ARM::lr; + static const RegisterID regStackPtr = ARMRegisters::sp; + static const RegisterID regLink = ARMRegisters::lr; - static const FPRegisterID fpRegT0 = ARM::d0; - static const FPRegisterID fpRegT1 = ARM::d1; - static const FPRegisterID fpRegT2 = ARM::d2; + static const FPRegisterID fpRegT0 = ARMRegisters::d0; + static const FPRegisterID fpRegT1 = ARMRegisters::d1; + static const FPRegisterID fpRegT2 = ARMRegisters::d2; #else #error "JIT not supported on this platform." #endif @@ -277,10 +278,9 @@ namespace JSC { static const int patchGetByIdDefaultOffset = 256; public: - static void compile(JSGlobalData* globalData, CodeBlock* codeBlock) + static JITCode compile(JSGlobalData* globalData, CodeBlock* codeBlock) { - JIT jit(globalData, codeBlock); - jit.privateCompile(); + return JIT(globalData, codeBlock).privateCompile(); } static void compileGetByIdProto(JSGlobalData* globalData, CallFrame* callFrame, CodeBlock* codeBlock, StructureStubInfo* stubInfo, Structure* structure, Structure* prototypeStructure, size_t cachedOffset, ReturnAddressPtr returnAddress) @@ -353,7 +353,7 @@ namespace JSC { void privateCompileMainPass(); void privateCompileLinkPass(); void privateCompileSlowCases(); - void privateCompile(); + JITCode privateCompile(); void privateCompileGetByIdProto(StructureStubInfo*, Structure*, Structure* prototypeStructure, size_t cachedOffset, ReturnAddressPtr returnAddress, CallFrame* callFrame); void privateCompileGetByIdSelfList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, size_t cachedOffset); void privateCompileGetByIdProtoList(StructureStubInfo*, PolymorphicAccessStructureList*, int, Structure*, Structure* prototypeStructure, size_t cachedOffset, CallFrame* callFrame); @@ -380,14 +380,20 @@ namespace JSC { enum CompileOpStrictEqType { OpStrictEq, OpNStrictEq }; void compileOpStrictEq(Instruction* instruction, CompileOpStrictEqType type); + bool isOperandConstantImmediateDouble(unsigned src); + + void emitLoadDouble(unsigned index, FPRegisterID value); + void emitLoadInt32ToDouble(unsigned index, FPRegisterID value); + + Address addressFor(unsigned index, RegisterID base = callFrameRegister); + + void testPrototype(Structure*, JumpList& failureCases); #if USE(JSVALUE32_64) Address tagFor(unsigned index, RegisterID base = callFrameRegister); Address payloadFor(unsigned index, RegisterID base = callFrameRegister); - Address addressFor(unsigned index, RegisterID base = callFrameRegister); bool getOperandConstantImmediateInt(unsigned op1, unsigned op2, unsigned& op, int32_t& constant); - bool isOperandConstantImmediateDouble(unsigned src); void emitLoadTag(unsigned index, RegisterID tag); void emitLoadPayload(unsigned index, RegisterID payload); @@ -395,8 +401,6 @@ namespace JSC { void emitLoad(const JSValue& v, RegisterID tag, RegisterID payload); void emitLoad(unsigned index, RegisterID tag, RegisterID payload, RegisterID base = callFrameRegister); void emitLoad2(unsigned index1, RegisterID tag1, RegisterID payload1, unsigned index2, RegisterID tag2, RegisterID payload2); - void emitLoadDouble(unsigned index, FPRegisterID value); - void emitLoadInt32ToDouble(unsigned index, FPRegisterID value); void emitStore(unsigned index, RegisterID tag, RegisterID payload, RegisterID base = callFrameRegister); void emitStore(unsigned index, const JSValue constant, RegisterID base = callFrameRegister); @@ -424,6 +428,7 @@ namespace JSC { #endif void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, Structure* structure, size_t cachedOffset); void compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID resultTag, RegisterID resultPayload, size_t cachedOffset); + void compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID structure, RegisterID offset); void compilePutDirectOffset(RegisterID base, RegisterID valueTag, RegisterID valuePayload, Structure* structure, size_t cachedOffset); // Arithmetic opcode helpers @@ -460,6 +465,47 @@ namespace JSC { static const int patchOffsetMethodCheckProtoObj = 11; static const int patchOffsetMethodCheckProtoStruct = 18; static const int patchOffsetMethodCheckPutFunction = 29; +#elif PLATFORM(ARM_TRADITIONAL) + // These architecture specific value are used to enable patching - see comment on op_put_by_id. + static const int patchOffsetPutByIdStructure = 4; + static const int patchOffsetPutByIdExternalLoad = 16; + static const int patchLengthPutByIdExternalLoad = 4; + static const int patchOffsetPutByIdPropertyMapOffset1 = 20; + static const int patchOffsetPutByIdPropertyMapOffset2 = 28; + // These architecture specific value are used to enable patching - see comment on op_get_by_id. + static const int patchOffsetGetByIdStructure = 4; + static const int patchOffsetGetByIdBranchToSlowCase = 16; + static const int patchOffsetGetByIdExternalLoad = 16; + static const int patchLengthGetByIdExternalLoad = 4; + static const int patchOffsetGetByIdPropertyMapOffset1 = 20; + static const int patchOffsetGetByIdPropertyMapOffset2 = 28; + static const int patchOffsetGetByIdPutResult = 36; +#if ENABLE(OPCODE_SAMPLING) + #error "OPCODE_SAMPLING is not yet supported" +#else + static const int patchOffsetGetByIdSlowCaseCall = 32; +#endif + static const int patchOffsetOpCallCompareToJump = 12; + + static const int patchOffsetMethodCheckProtoObj = 12; + static const int patchOffsetMethodCheckProtoStruct = 20; + static const int patchOffsetMethodCheckPutFunction = 32; + + // sequenceOpCall + static const int sequenceOpCallInstructionSpace = 12; + static const int sequenceOpCallConstantSpace = 2; + // sequenceMethodCheck + static const int sequenceMethodCheckInstructionSpace = 40; + static const int sequenceMethodCheckConstantSpace = 6; + // sequenceGetByIdHotPath + static const int sequenceGetByIdHotPathInstructionSpace = 36; + static const int sequenceGetByIdHotPathConstantSpace = 4; + // sequenceGetByIdSlowCase + static const int sequenceGetByIdSlowCaseInstructionSpace = 40; + static const int sequenceGetByIdSlowCaseConstantSpace = 2; + // sequencePutById + static const int sequencePutByIdInstructionSpace = 36; + static const int sequencePutByIdConstantSpace = 4; #else #error "JSVALUE32_64 not supported on this platform." #endif @@ -500,6 +546,7 @@ namespace JSC { JIT::Jump emitJumpIfNotImmediateInteger(RegisterID); JIT::Jump emitJumpIfNotImmediateIntegers(RegisterID, RegisterID, RegisterID); void emitJumpSlowCaseIfNotImmediateInteger(RegisterID); + void emitJumpSlowCaseIfNotImmediateNumber(RegisterID); void emitJumpSlowCaseIfNotImmediateIntegers(RegisterID, RegisterID, RegisterID); #if !USE(JSVALUE64) @@ -512,7 +559,11 @@ namespace JSC { void emitTagAsBoolImmediate(RegisterID reg); void compileBinaryArithOp(OpcodeID, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi); - void compileBinaryArithOpSlowCase(OpcodeID, Vector<SlowCaseEntry>::iterator&, unsigned dst, unsigned src1, unsigned src2, OperandTypes opi); +#if USE(JSVALUE64) + void compileBinaryArithOpSlowCase(OpcodeID, Vector<SlowCaseEntry>::iterator&, unsigned dst, unsigned src1, unsigned src2, OperandTypes, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase); +#else + void compileBinaryArithOpSlowCase(OpcodeID, Vector<SlowCaseEntry>::iterator&, unsigned dst, unsigned src1, unsigned src2, OperandTypes); +#endif #if ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) void compileGetByIdHotPath(int resultVReg, int baseVReg, Identifier* ident, unsigned propertyAccessInstructionIndex); @@ -520,6 +571,7 @@ namespace JSC { #endif void compileGetDirectOffset(RegisterID base, RegisterID result, Structure* structure, size_t cachedOffset); void compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID result, size_t cachedOffset); + void compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID structure, RegisterID offset, RegisterID scratch); void compilePutDirectOffset(RegisterID base, RegisterID value, Structure* structure, size_t cachedOffset); #if PLATFORM(X86_64) @@ -536,7 +588,7 @@ namespace JSC { static const int patchOffsetGetByIdPropertyMapOffset = 31; static const int patchOffsetGetByIdPutResult = 31; #if ENABLE(OPCODE_SAMPLING) - static const int patchOffsetGetByIdSlowCaseCall = 63; + static const int patchOffsetGetByIdSlowCaseCall = 64; #else static const int patchOffsetGetByIdSlowCaseCall = 41; #endif @@ -572,32 +624,83 @@ namespace JSC { static const int patchOffsetMethodCheckProtoObj = 11; static const int patchOffsetMethodCheckProtoStruct = 18; static const int patchOffsetMethodCheckPutFunction = 29; -#elif PLATFORM_ARM_ARCH(7) +#elif PLATFORM(ARM_THUMB2) // These architecture specific value are used to enable patching - see comment on op_put_by_id. static const int patchOffsetPutByIdStructure = 10; - static const int patchOffsetPutByIdExternalLoad = 20; + static const int patchOffsetPutByIdExternalLoad = 26; static const int patchLengthPutByIdExternalLoad = 12; - static const int patchOffsetPutByIdPropertyMapOffset = 40; + static const int patchOffsetPutByIdPropertyMapOffset = 46; // These architecture specific value are used to enable patching - see comment on op_get_by_id. static const int patchOffsetGetByIdStructure = 10; - static const int patchOffsetGetByIdBranchToSlowCase = 20; - static const int patchOffsetGetByIdExternalLoad = 20; + static const int patchOffsetGetByIdBranchToSlowCase = 26; + static const int patchOffsetGetByIdExternalLoad = 26; static const int patchLengthGetByIdExternalLoad = 12; - static const int patchOffsetGetByIdPropertyMapOffset = 40; - static const int patchOffsetGetByIdPutResult = 44; + static const int patchOffsetGetByIdPropertyMapOffset = 46; + static const int patchOffsetGetByIdPutResult = 50; #if ENABLE(OPCODE_SAMPLING) static const int patchOffsetGetByIdSlowCaseCall = 0; // FIMXE #else static const int patchOffsetGetByIdSlowCaseCall = 28; #endif - static const int patchOffsetOpCallCompareToJump = 10; + static const int patchOffsetOpCallCompareToJump = 16; - static const int patchOffsetMethodCheckProtoObj = 18; - static const int patchOffsetMethodCheckProtoStruct = 28; - static const int patchOffsetMethodCheckPutFunction = 46; + static const int patchOffsetMethodCheckProtoObj = 24; + static const int patchOffsetMethodCheckProtoStruct = 34; + static const int patchOffsetMethodCheckPutFunction = 58; +#elif PLATFORM(ARM_TRADITIONAL) + // These architecture specific value are used to enable patching - see comment on op_put_by_id. + static const int patchOffsetPutByIdStructure = 4; + static const int patchOffsetPutByIdExternalLoad = 16; + static const int patchLengthPutByIdExternalLoad = 4; + static const int patchOffsetPutByIdPropertyMapOffset = 20; + // These architecture specific value are used to enable patching - see comment on op_get_by_id. + static const int patchOffsetGetByIdStructure = 4; + static const int patchOffsetGetByIdBranchToSlowCase = 16; + static const int patchOffsetGetByIdExternalLoad = 16; + static const int patchLengthGetByIdExternalLoad = 4; + static const int patchOffsetGetByIdPropertyMapOffset = 20; + static const int patchOffsetGetByIdPutResult = 28; +#if ENABLE(OPCODE_SAMPLING) + #error "OPCODE_SAMPLING is not yet supported" +#else + static const int patchOffsetGetByIdSlowCaseCall = 28; +#endif + static const int patchOffsetOpCallCompareToJump = 12; + + static const int patchOffsetMethodCheckProtoObj = 12; + static const int patchOffsetMethodCheckProtoStruct = 20; + static const int patchOffsetMethodCheckPutFunction = 32; + + // sequenceOpCall + static const int sequenceOpCallInstructionSpace = 12; + static const int sequenceOpCallConstantSpace = 2; + // sequenceMethodCheck + static const int sequenceMethodCheckInstructionSpace = 40; + static const int sequenceMethodCheckConstantSpace = 6; + // sequenceGetByIdHotPath + static const int sequenceGetByIdHotPathInstructionSpace = 28; + static const int sequenceGetByIdHotPathConstantSpace = 3; + // sequenceGetByIdSlowCase + static const int sequenceGetByIdSlowCaseInstructionSpace = 32; + static const int sequenceGetByIdSlowCaseConstantSpace = 2; + // sequencePutById + static const int sequencePutByIdInstructionSpace = 28; + static const int sequencePutByIdConstantSpace = 3; #endif #endif // USE(JSVALUE32_64) +#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL +#define BEGIN_UNINTERRUPTED_SEQUENCE(name) beginUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace) +#define END_UNINTERRUPTED_SEQUENCE(name) endUninterruptedSequence(name ## InstructionSpace, name ## ConstantSpace) + + void beginUninterruptedSequence(int, int); + void endUninterruptedSequence(int, int); + +#else +#define BEGIN_UNINTERRUPTED_SEQUENCE(name) +#define END_UNINTERRUPTED_SEQUENCE(name) +#endif + void emit_op_add(Instruction*); void emit_op_bitand(Instruction*); void emit_op_bitnot(Instruction*); @@ -621,6 +724,7 @@ namespace JSC { void emit_op_eq_null(Instruction*); void emit_op_get_by_id(Instruction*); void emit_op_get_by_val(Instruction*); + void emit_op_get_by_pname(Instruction*); void emit_op_get_global_var(Instruction*); void emit_op_get_scoped_var(Instruction*); void emit_op_init_arguments(Instruction*); @@ -632,6 +736,7 @@ namespace JSC { void emit_op_jneq_null(Instruction*); void emit_op_jneq_ptr(Instruction*); void emit_op_jnless(Instruction*); + void emit_op_jless(Instruction*); void emit_op_jnlesseq(Instruction*); void emit_op_jsr(Instruction*); void emit_op_jtrue(Instruction*); @@ -640,6 +745,7 @@ namespace JSC { void emit_op_loop_if_less(Instruction*); void emit_op_loop_if_lesseq(Instruction*); void emit_op_loop_if_true(Instruction*); + void emit_op_loop_if_false(Instruction*); void emit_op_lshift(Instruction*); void emit_op_method_check(Instruction*); void emit_op_mod(Instruction*); @@ -654,6 +760,7 @@ namespace JSC { void emit_op_new_func_exp(Instruction*); void emit_op_new_object(Instruction*); void emit_op_new_regexp(Instruction*); + void emit_op_get_pnames(Instruction*); void emit_op_next_pname(Instruction*); void emit_op_not(Instruction*); void emit_op_nstricteq(Instruction*); @@ -709,14 +816,17 @@ namespace JSC { void emitSlow_op_eq(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_get_by_id(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_get_by_val(Instruction*, Vector<SlowCaseEntry>::iterator&); + void emitSlow_op_get_by_pname(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_instanceof(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jfalse(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jnless(Instruction*, Vector<SlowCaseEntry>::iterator&); + void emitSlow_op_jless(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jnlesseq(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_jtrue(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_loop_if_less(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_loop_if_lesseq(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_loop_if_true(Instruction*, Vector<SlowCaseEntry>::iterator&); + void emitSlow_op_loop_if_false(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_lshift(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_method_check(Instruction*, Vector<SlowCaseEntry>::iterator&); void emitSlow_op_mod(Instruction*, Vector<SlowCaseEntry>::iterator&); @@ -741,6 +851,7 @@ namespace JSC { /* These functions are deprecated: Please use JITStubCall instead. */ void emitPutJITStubArg(RegisterID src, unsigned argumentNumber); #if USE(JSVALUE32_64) + void emitPutJITStubArg(RegisterID tag, RegisterID payload, unsigned argumentNumber); void emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch1, RegisterID scratch2); #else void emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch); @@ -835,6 +946,13 @@ namespace JSC { int m_lastResultBytecodeRegister; unsigned m_jumpTargetsPosition; #endif + +#ifndef NDEBUG +#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL + Label m_uninterruptedInstructionSequenceBegin; + int m_uninterruptedConstantSequenceBegin; +#endif +#endif } JIT_CLASS_ALIGNMENT; } // namespace JSC diff --git a/JavaScriptCore/jit/JITArithmetic.cpp b/JavaScriptCore/jit/JITArithmetic.cpp index ea343d8..70f7564 100644 --- a/JavaScriptCore/jit/JITArithmetic.cpp +++ b/JavaScriptCore/jit/JITArithmetic.cpp @@ -98,16 +98,16 @@ void JIT::emit_op_jnless(Instruction* currentInstruction) if (isOperandConstantImmediateInt(op1)) { emitLoad(op2, regT3, regT2); notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThanOrEqual, regT2, Imm32(getConstantOperand(op1).asInt32())), target + 3); + addJump(branch32(LessThanOrEqual, regT2, Imm32(getConstantOperand(op1).asInt32())), target); } else if (isOperandConstantImmediateInt(op2)) { emitLoad(op1, regT1, regT0); notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target + 3); + addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target); } else { emitLoad2(op1, regT1, regT0, op2, regT3, regT2); notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThanOrEqual, regT0, regT2), target + 3); + addJump(branch32(GreaterThanOrEqual, regT0, regT2), target); } if (!supportsFloatingPoint()) { @@ -145,7 +145,70 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt stubCall.addArgument(op1); stubCall.addArgument(op2); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); +} + +void JIT::emit_op_jless(Instruction* currentInstruction) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + JumpList notInt32Op1; + JumpList notInt32Op2; + + // Int32 less. + if (isOperandConstantImmediateInt(op1)) { + emitLoad(op2, regT3, regT2); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(GreaterThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target); + } else if (isOperandConstantImmediateInt(op2)) { + emitLoad(op1, regT1, regT0); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + addJump(branch32(LessThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target); + } else { + emitLoad2(op1, regT1, regT0, op2, regT3, regT2); + notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); + notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); + addJump(branch32(LessThan, regT0, regT2), target); + } + + if (!supportsFloatingPoint()) { + addSlowCase(notInt32Op1); + addSlowCase(notInt32Op2); + return; + } + Jump end = jump(); + + // Double less. + emitBinaryDoubleOp(op_jless, target, op1, op2, OperandTypes(), notInt32Op1, notInt32Op2, !isOperandConstantImmediateInt(op1), isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)); + end.link(this); +} + +void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + if (!supportsFloatingPoint()) { + if (!isOperandConstantImmediateInt(op1) && !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // int32 check + linkSlowCase(iter); // int32 check + } else { + if (!isOperandConstantImmediateInt(op1)) { + linkSlowCase(iter); // double check + linkSlowCase(iter); // int32 check + } + if (isOperandConstantImmediateInt(op1) || !isOperandConstantImmediateInt(op2)) + linkSlowCase(iter); // double check + } + + JITStubCall stubCall(this, cti_op_jless); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } void JIT::emit_op_jnlesseq(Instruction* currentInstruction) @@ -161,16 +224,16 @@ void JIT::emit_op_jnlesseq(Instruction* currentInstruction) if (isOperandConstantImmediateInt(op1)) { emitLoad(op2, regT3, regT2); notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target + 3); + addJump(branch32(LessThan, regT2, Imm32(getConstantOperand(op1).asInt32())), target); } else if (isOperandConstantImmediateInt(op2)) { emitLoad(op1, regT1, regT0); notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target + 3); + addJump(branch32(GreaterThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target); } else { emitLoad2(op1, regT1, regT0, op2, regT3, regT2); notInt32Op1.append(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); notInt32Op2.append(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThan, regT0, regT2), target + 3); + addJump(branch32(GreaterThan, regT0, regT2), target); } if (!supportsFloatingPoint()) { @@ -208,7 +271,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE stubCall.addArgument(op1); stubCall.addArgument(op2); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); } // LeftShift (<<) @@ -566,6 +629,14 @@ void JIT::emit_op_add(Instruction* currentInstruction) unsigned op2 = currentInstruction[3].u.operand; OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) { + JITStubCall stubCall(this, cti_op_add); + stubCall.addArgument(op1); + stubCall.addArgument(op2); + stubCall.call(dst); + return; + } + JumpList notInt32Op1; JumpList notInt32Op2; @@ -630,19 +701,21 @@ void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry> unsigned op2 = currentInstruction[3].u.operand; OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) + return; + unsigned op; int32_t constant; if (getOperandConstantImmediateInt(op1, op2, op, constant)) { linkSlowCase(iter); // overflow check - if (!supportsFloatingPoint()) { + if (!supportsFloatingPoint()) linkSlowCase(iter); // non-sse case - return; + else { + ResultType opType = op == op1 ? types.first() : types.second(); + if (!opType.definitelyIsNumber()) + linkSlowCase(iter); // double check } - - ResultType opType = op == op1 ? types.first() : types.second(); - if (!opType.definitelyIsNumber()) - linkSlowCase(iter); // double check } else { linkSlowCase(iter); // overflow check @@ -819,11 +892,15 @@ void JIT::emitBinaryDoubleOp(OpcodeID opcodeID, unsigned dst, unsigned op1, unsi break; case op_jnless: emitLoadDouble(op1, fpRegT2); - addJump(branchDouble(DoubleLessThanOrEqual, fpRegT0, fpRegT2), dst + 3); + addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT0, fpRegT2), dst); + break; + case op_jless: + emitLoadDouble(op1, fpRegT2); + addJump(branchDouble(DoubleLessThan, fpRegT2, fpRegT0), dst); break; case op_jnlesseq: emitLoadDouble(op1, fpRegT2); - addJump(branchDouble(DoubleLessThan, fpRegT0, fpRegT2), dst + 3); + addJump(branchDouble(DoubleLessThanOrUnordered, fpRegT0, fpRegT2), dst); break; default: ASSERT_NOT_REACHED(); @@ -872,11 +949,15 @@ void JIT::emitBinaryDoubleOp(OpcodeID opcodeID, unsigned dst, unsigned op1, unsi break; case op_jnless: emitLoadDouble(op2, fpRegT1); - addJump(branchDouble(DoubleLessThanOrEqual, fpRegT1, fpRegT0), dst + 3); + addJump(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), dst); + break; + case op_jless: + emitLoadDouble(op2, fpRegT1); + addJump(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), dst); break; case op_jnlesseq: emitLoadDouble(op2, fpRegT1); - addJump(branchDouble(DoubleLessThan, fpRegT1, fpRegT0), dst + 3); + addJump(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), dst); break; default: ASSERT_NOT_REACHED(); @@ -990,20 +1071,11 @@ void JIT::emit_op_div(Instruction* currentInstruction) divDouble(fpRegT1, fpRegT0); JumpList doubleResult; - if (!isOperandConstantImmediateInt(op1) || getConstantOperand(op1).asInt32() > 1) { - m_assembler.cvttsd2si_rr(fpRegT0, regT0); - convertInt32ToDouble(regT0, fpRegT1); - m_assembler.ucomisd_rr(fpRegT1, fpRegT0); + branchConvertDoubleToInt32(fpRegT0, regT0, doubleResult, fpRegT1); - doubleResult.append(m_assembler.jne()); - doubleResult.append(m_assembler.jp()); - - doubleResult.append(branchTest32(Zero, regT0)); - - // Int32 result. - emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); - end.append(jump()); - } + // Int32 result. + emitStoreInt32(dst, regT0, (op1 == dst || op2 == dst)); + end.append(jump()); // Double result. doubleResult.link(this); @@ -1053,33 +1125,33 @@ void JIT::emit_op_mod(Instruction* currentInstruction) unsigned op2 = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op2) && getConstantOperand(op2).asInt32() != 0) { - emitLoad(op1, X86::edx, X86::eax); - move(Imm32(getConstantOperand(op2).asInt32()), X86::ecx); - addSlowCase(branch32(NotEqual, X86::edx, Imm32(JSValue::Int32Tag))); + emitLoad(op1, X86Registers::edx, X86Registers::eax); + move(Imm32(getConstantOperand(op2).asInt32()), X86Registers::ecx); + addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag))); if (getConstantOperand(op2).asInt32() == -1) - addSlowCase(branch32(Equal, X86::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC + addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC } else { - emitLoad2(op1, X86::edx, X86::eax, op2, X86::ebx, X86::ecx); - addSlowCase(branch32(NotEqual, X86::edx, Imm32(JSValue::Int32Tag))); - addSlowCase(branch32(NotEqual, X86::ebx, Imm32(JSValue::Int32Tag))); + emitLoad2(op1, X86Registers::edx, X86Registers::eax, op2, X86Registers::ebx, X86Registers::ecx); + addSlowCase(branch32(NotEqual, X86Registers::edx, Imm32(JSValue::Int32Tag))); + addSlowCase(branch32(NotEqual, X86Registers::ebx, Imm32(JSValue::Int32Tag))); - addSlowCase(branch32(Equal, X86::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC - addSlowCase(branch32(Equal, X86::ecx, Imm32(0))); // divide by 0 + addSlowCase(branch32(Equal, X86Registers::eax, Imm32(0x80000000))); // -2147483648 / -1 => EXC_ARITHMETIC + addSlowCase(branch32(Equal, X86Registers::ecx, Imm32(0))); // divide by 0 } - move(X86::eax, X86::ebx); // Save dividend payload, in case of 0. + move(X86Registers::eax, X86Registers::ebx); // Save dividend payload, in case of 0. m_assembler.cdq(); - m_assembler.idivl_r(X86::ecx); + m_assembler.idivl_r(X86Registers::ecx); // If the remainder is zero and the dividend is negative, the result is -0. - Jump storeResult1 = branchTest32(NonZero, X86::edx); - Jump storeResult2 = branchTest32(Zero, X86::ebx, Imm32(0x80000000)); // not negative + Jump storeResult1 = branchTest32(NonZero, X86Registers::edx); + Jump storeResult2 = branchTest32(Zero, X86Registers::ebx, Imm32(0x80000000)); // not negative emitStore(dst, jsNumber(m_globalData, -0.0)); Jump end = jump(); storeResult1.link(this); storeResult2.link(this); - emitStoreInt32(dst, X86::edx, (op1 == dst || op2 == dst)); + emitStoreInt32(dst, X86Registers::edx, (op1 == dst || op2 == dst)); end.link(this); } @@ -1142,13 +1214,8 @@ void JIT::emit_op_lshift(Instruction* currentInstruction) emitJumpSlowCaseIfNotImmediateInteger(regT2); emitFastArithImmToInt(regT0); emitFastArithImmToInt(regT2); -#if !PLATFORM(X86) - // Mask with 0x1f as per ecma-262 11.7.2 step 7. - // On 32-bit x86 this is not necessary, since the shift anount is implicitly masked in the instruction. - and32(Imm32(0x1f), regT2); -#endif lshift32(regT2, regT0); -#if !USE(JSVALUE64) +#if USE(JSVALUE32) addSlowCase(branchAdd32(Overflow, regT0, regT0)); signExtend32ToPtr(regT0, regT0); #endif @@ -1193,11 +1260,7 @@ void JIT::emit_op_rshift(Instruction* currentInstruction) emitGetVirtualRegister(op1, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); // Mask with 0x1f as per ecma-262 11.7.2 step 7. -#if USE(JSVALUE64) rshift32(Imm32(getConstantOperandImmediateInt(op2) & 0x1f), regT0); -#else - rshiftPtr(Imm32(getConstantOperandImmediateInt(op2) & 0x1f), regT0); -#endif } else { emitGetVirtualRegisters(op1, regT0, op2, regT2); if (supportsFloatingPointTruncate()) { @@ -1224,15 +1287,9 @@ void JIT::emit_op_rshift(Instruction* currentInstruction) emitJumpSlowCaseIfNotImmediateInteger(regT2); } emitFastArithImmToInt(regT2); -#if !PLATFORM(X86) - // Mask with 0x1f as per ecma-262 11.7.2 step 7. - // On 32-bit x86 this is not necessary, since the shift anount is implicitly masked in the instruction. - and32(Imm32(0x1f), regT2); -#endif -#if USE(JSVALUE64) rshift32(regT2, regT0); -#else - rshiftPtr(regT2, regT0); +#if USE(JSVALUE32) + signExtend32ToPtr(regT0, regT0); #endif } #if USE(JSVALUE64) @@ -1303,7 +1360,7 @@ void JIT::emit_op_jnless(Instruction* currentInstruction) #else int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2))); #endif - addJump(branch32(GreaterThanOrEqual, regT0, Imm32(op2imm)), target + 3); + addJump(branch32(GreaterThanOrEqual, regT0, Imm32(op2imm)), target); } else if (isOperandConstantImmediateInt(op1)) { emitGetVirtualRegister(op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT1); @@ -1312,13 +1369,13 @@ void JIT::emit_op_jnless(Instruction* currentInstruction) #else int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1))); #endif - addJump(branch32(LessThanOrEqual, regT1, Imm32(op1imm)), target + 3); + addJump(branch32(LessThanOrEqual, regT1, Imm32(op1imm)), target); } else { emitGetVirtualRegisters(op1, regT0, op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); - addJump(branch32(GreaterThanOrEqual, regT0, regT1), target + 3); + addJump(branch32(GreaterThanOrEqual, regT0, regT1), target); } } @@ -1355,7 +1412,7 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt move(Imm32(op2imm), regT1); convertInt32ToDouble(regT1, fpRegT1); - emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqual, fpRegT1, fpRegT0), target + 3); + emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); @@ -1372,7 +1429,7 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt stubCall.addArgument(regT0); stubCall.addArgument(op2, regT2); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); } else if (isOperandConstantImmediateInt(op1)) { linkSlowCase(iter); @@ -1396,7 +1453,192 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt move(Imm32(op1imm), regT0); convertInt32ToDouble(regT0, fpRegT0); - emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqual, fpRegT1, fpRegT0), target + 3); + emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target); + + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); + +#if USE(JSVALUE64) + fail1.link(this); +#else + if (!m_codeBlock->isKnownNotImmediate(op2)) + fail1.link(this); + fail2.link(this); +#endif + } + + JITStubCall stubCall(this, cti_op_jless); + stubCall.addArgument(op1, regT2); + stubCall.addArgument(regT1); + stubCall.call(); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); + + } else { + linkSlowCase(iter); + + if (supportsFloatingPoint()) { +#if USE(JSVALUE64) + Jump fail1 = emitJumpIfNotImmediateNumber(regT0); + Jump fail2 = emitJumpIfNotImmediateNumber(regT1); + Jump fail3 = emitJumpIfImmediateInteger(regT1); + addPtr(tagTypeNumberRegister, regT0); + addPtr(tagTypeNumberRegister, regT1); + movePtrToDouble(regT0, fpRegT0); + movePtrToDouble(regT1, fpRegT1); +#else + Jump fail1; + if (!m_codeBlock->isKnownNotImmediate(op1)) + fail1 = emitJumpIfNotJSCell(regT0); + + Jump fail2; + if (!m_codeBlock->isKnownNotImmediate(op2)) + fail2 = emitJumpIfNotJSCell(regT1); + + Jump fail3 = checkStructure(regT0, m_globalData->numberStructure.get()); + Jump fail4 = checkStructure(regT1, m_globalData->numberStructure.get()); + loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0); + loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1); +#endif + + emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqualOrUnordered, fpRegT1, fpRegT0), target); + + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); + +#if USE(JSVALUE64) + fail1.link(this); + fail2.link(this); + fail3.link(this); +#else + if (!m_codeBlock->isKnownNotImmediate(op1)) + fail1.link(this); + if (!m_codeBlock->isKnownNotImmediate(op2)) + fail2.link(this); + fail3.link(this); + fail4.link(this); +#endif + } + + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_jless); + stubCall.addArgument(regT0); + stubCall.addArgument(regT1); + stubCall.call(); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); + } +} + +void JIT::emit_op_jless(Instruction* currentInstruction) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + // We generate inline code for the following cases in the fast path: + // - int immediate to constant int immediate + // - constant int immediate to int immediate + // - int immediate to int immediate + + if (isOperandConstantImmediateInt(op2)) { + emitGetVirtualRegister(op1, regT0); + emitJumpSlowCaseIfNotImmediateInteger(regT0); +#if USE(JSVALUE64) + int32_t op2imm = getConstantOperandImmediateInt(op2); +#else + int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2))); +#endif + addJump(branch32(LessThan, regT0, Imm32(op2imm)), target); + } else if (isOperandConstantImmediateInt(op1)) { + emitGetVirtualRegister(op2, regT1); + emitJumpSlowCaseIfNotImmediateInteger(regT1); +#if USE(JSVALUE64) + int32_t op1imm = getConstantOperandImmediateInt(op1); +#else + int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1))); +#endif + addJump(branch32(GreaterThan, regT1, Imm32(op1imm)), target); + } else { + emitGetVirtualRegisters(op1, regT0, op2, regT1); + emitJumpSlowCaseIfNotImmediateInteger(regT0); + emitJumpSlowCaseIfNotImmediateInteger(regT1); + + addJump(branch32(LessThan, regT0, regT1), target); + } +} + +void JIT::emitSlow_op_jless(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned op1 = currentInstruction[1].u.operand; + unsigned op2 = currentInstruction[2].u.operand; + unsigned target = currentInstruction[3].u.operand; + + // We generate inline code for the following cases in the slow path: + // - floating-point number to constant int immediate + // - constant int immediate to floating-point number + // - floating-point number to floating-point number. + + if (isOperandConstantImmediateInt(op2)) { + linkSlowCase(iter); + + if (supportsFloatingPoint()) { +#if USE(JSVALUE64) + Jump fail1 = emitJumpIfNotImmediateNumber(regT0); + addPtr(tagTypeNumberRegister, regT0); + movePtrToDouble(regT0, fpRegT0); +#else + Jump fail1; + if (!m_codeBlock->isKnownNotImmediate(op1)) + fail1 = emitJumpIfNotJSCell(regT0); + + Jump fail2 = checkStructure(regT0, m_globalData->numberStructure.get()); + loadDouble(Address(regT0, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT0); +#endif + + int32_t op2imm = getConstantOperand(op2).asInt32(); + + move(Imm32(op2imm), regT1); + convertInt32ToDouble(regT1, fpRegT1); + + emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target); + + emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); + +#if USE(JSVALUE64) + fail1.link(this); +#else + if (!m_codeBlock->isKnownNotImmediate(op1)) + fail1.link(this); + fail2.link(this); +#endif + } + + JITStubCall stubCall(this, cti_op_jless); + stubCall.addArgument(regT0); + stubCall.addArgument(op2, regT2); + stubCall.call(); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); + + } else if (isOperandConstantImmediateInt(op1)) { + linkSlowCase(iter); + + if (supportsFloatingPoint()) { +#if USE(JSVALUE64) + Jump fail1 = emitJumpIfNotImmediateNumber(regT1); + addPtr(tagTypeNumberRegister, regT1); + movePtrToDouble(regT1, fpRegT1); +#else + Jump fail1; + if (!m_codeBlock->isKnownNotImmediate(op2)) + fail1 = emitJumpIfNotJSCell(regT1); + + Jump fail2 = checkStructure(regT1, m_globalData->numberStructure.get()); + loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1); +#endif + + int32_t op1imm = getConstantOperand(op1).asInt32(); + + move(Imm32(op1imm), regT0); + convertInt32ToDouble(regT0, fpRegT0); + + emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); @@ -1413,7 +1655,7 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt stubCall.addArgument(op1, regT2); stubCall.addArgument(regT1); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } else { linkSlowCase(iter); @@ -1442,7 +1684,7 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1); #endif - emitJumpSlowToHot(branchDouble(DoubleLessThanOrEqual, fpRegT1, fpRegT0), target + 3); + emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT0, fpRegT1), target); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnless)); @@ -1465,7 +1707,7 @@ void JIT::emitSlow_op_jnless(Instruction* currentInstruction, Vector<SlowCaseEnt stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } } @@ -1488,7 +1730,7 @@ void JIT::emit_op_jnlesseq(Instruction* currentInstruction) #else int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2))); #endif - addJump(branch32(GreaterThan, regT0, Imm32(op2imm)), target + 3); + addJump(branch32(GreaterThan, regT0, Imm32(op2imm)), target); } else if (isOperandConstantImmediateInt(op1)) { emitGetVirtualRegister(op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT1); @@ -1497,13 +1739,13 @@ void JIT::emit_op_jnlesseq(Instruction* currentInstruction) #else int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1))); #endif - addJump(branch32(LessThan, regT1, Imm32(op1imm)), target + 3); + addJump(branch32(LessThan, regT1, Imm32(op1imm)), target); } else { emitGetVirtualRegisters(op1, regT0, op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); - addJump(branch32(GreaterThan, regT0, regT1), target + 3); + addJump(branch32(GreaterThan, regT0, regT1), target); } } @@ -1540,7 +1782,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE move(Imm32(op2imm), regT1); convertInt32ToDouble(regT1, fpRegT1); - emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT1, fpRegT0), target + 3); + emitJumpSlowToHot(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), target); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq)); @@ -1557,7 +1799,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE stubCall.addArgument(regT0); stubCall.addArgument(op2, regT2); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); } else if (isOperandConstantImmediateInt(op1)) { linkSlowCase(iter); @@ -1581,7 +1823,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE move(Imm32(op1imm), regT0); convertInt32ToDouble(regT0, fpRegT0); - emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT1, fpRegT0), target + 3); + emitJumpSlowToHot(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), target); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq)); @@ -1598,7 +1840,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE stubCall.addArgument(op1, regT2); stubCall.addArgument(regT1); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); } else { linkSlowCase(iter); @@ -1627,7 +1869,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE loadDouble(Address(regT1, OBJECT_OFFSETOF(JSNumberCell, m_value)), fpRegT1); #endif - emitJumpSlowToHot(branchDouble(DoubleLessThan, fpRegT1, fpRegT0), target + 3); + emitJumpSlowToHot(branchDouble(DoubleLessThanOrUnordered, fpRegT1, fpRegT0), target); emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_jnlesseq)); @@ -1650,7 +1892,7 @@ void JIT::emitSlow_op_jnlesseq(Instruction* currentInstruction, Vector<SlowCaseE stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); } } @@ -1847,21 +2089,21 @@ void JIT::emit_op_mod(Instruction* currentInstruction) unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; - emitGetVirtualRegisters(op1, X86::eax, op2, X86::ecx); - emitJumpSlowCaseIfNotImmediateInteger(X86::eax); - emitJumpSlowCaseIfNotImmediateInteger(X86::ecx); + emitGetVirtualRegisters(op1, X86Registers::eax, op2, X86Registers::ecx); + emitJumpSlowCaseIfNotImmediateInteger(X86Registers::eax); + emitJumpSlowCaseIfNotImmediateInteger(X86Registers::ecx); #if USE(JSVALUE64) - addSlowCase(branchPtr(Equal, X86::ecx, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0))))); + addSlowCase(branchPtr(Equal, X86Registers::ecx, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0))))); m_assembler.cdq(); - m_assembler.idivl_r(X86::ecx); + m_assembler.idivl_r(X86Registers::ecx); #else - emitFastArithDeTagImmediate(X86::eax); - addSlowCase(emitFastArithDeTagImmediateJumpIfZero(X86::ecx)); + emitFastArithDeTagImmediate(X86Registers::eax); + addSlowCase(emitFastArithDeTagImmediateJumpIfZero(X86Registers::ecx)); m_assembler.cdq(); - m_assembler.idivl_r(X86::ecx); - signExtend32ToPtr(X86::edx, X86::edx); + m_assembler.idivl_r(X86Registers::ecx); + signExtend32ToPtr(X86Registers::edx, X86Registers::edx); #endif - emitFastArithReTagImmediate(X86::edx, X86::eax); + emitFastArithReTagImmediate(X86Registers::edx, X86Registers::eax); emitPutVirtualRegister(result); } @@ -1877,14 +2119,14 @@ void JIT::emitSlow_op_mod(Instruction* currentInstruction, Vector<SlowCaseEntry> Jump notImm1 = getSlowCase(iter); Jump notImm2 = getSlowCase(iter); linkSlowCase(iter); - emitFastArithReTagImmediate(X86::eax, X86::eax); - emitFastArithReTagImmediate(X86::ecx, X86::ecx); + emitFastArithReTagImmediate(X86Registers::eax, X86Registers::eax); + emitFastArithReTagImmediate(X86Registers::ecx, X86Registers::ecx); notImm1.link(this); notImm2.link(this); #endif JITStubCall stubCall(this, cti_op_mod); - stubCall.addArgument(X86::eax); - stubCall.addArgument(X86::ecx); + stubCall.addArgument(X86Registers::eax); + stubCall.addArgument(X86Registers::ecx); stubCall.call(result); } @@ -1932,55 +2174,87 @@ void JIT::compileBinaryArithOp(OpcodeID opcodeID, unsigned, unsigned op1, unsign emitFastArithIntToImmNoCheck(regT0, regT0); } -void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned result, unsigned op1, unsigned, OperandTypes types) +void JIT::compileBinaryArithOpSlowCase(OpcodeID opcodeID, Vector<SlowCaseEntry>::iterator& iter, unsigned result, unsigned op1, unsigned op2, OperandTypes types, bool op1HasImmediateIntFastCase, bool op2HasImmediateIntFastCase) { // We assume that subtracting TagTypeNumber is equivalent to adding DoubleEncodeOffset. COMPILE_ASSERT(((JSImmediate::TagTypeNumber + JSImmediate::DoubleEncodeOffset) == 0), TagTypeNumber_PLUS_DoubleEncodeOffset_EQUALS_0); - - Jump notImm1 = getSlowCase(iter); - Jump notImm2 = getSlowCase(iter); + + Jump notImm1; + Jump notImm2; + if (op1HasImmediateIntFastCase) { + notImm2 = getSlowCase(iter); + } else if (op2HasImmediateIntFastCase) { + notImm1 = getSlowCase(iter); + } else { + notImm1 = getSlowCase(iter); + notImm2 = getSlowCase(iter); + } linkSlowCase(iter); // Integer overflow case - we could handle this in JIT code, but this is likely rare. - if (opcodeID == op_mul) // op_mul has an extra slow case to handle 0 * negative number. + if (opcodeID == op_mul && !op1HasImmediateIntFastCase && !op2HasImmediateIntFastCase) // op_mul has an extra slow case to handle 0 * negative number. linkSlowCase(iter); emitGetVirtualRegister(op1, regT0); Label stubFunctionCall(this); JITStubCall stubCall(this, opcodeID == op_add ? cti_op_add : opcodeID == op_sub ? cti_op_sub : cti_op_mul); + if (op1HasImmediateIntFastCase || op2HasImmediateIntFastCase) { + emitGetVirtualRegister(op1, regT0); + emitGetVirtualRegister(op2, regT1); + } stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(result); Jump end = jump(); - // if we get here, eax is not an int32, edx not yet checked. - notImm1.link(this); - if (!types.first().definitelyIsNumber()) - emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); - if (!types.second().definitelyIsNumber()) - emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this); - addPtr(tagTypeNumberRegister, regT0); - movePtrToDouble(regT0, fpRegT1); - Jump op2isDouble = emitJumpIfNotImmediateInteger(regT1); - convertInt32ToDouble(regT1, fpRegT2); - Jump op2wasInteger = jump(); - - // if we get here, eax IS an int32, edx is not. - notImm2.link(this); - if (!types.second().definitelyIsNumber()) - emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this); - convertInt32ToDouble(regT0, fpRegT1); - op2isDouble.link(this); - addPtr(tagTypeNumberRegister, regT1); - movePtrToDouble(regT1, fpRegT2); - op2wasInteger.link(this); + if (op1HasImmediateIntFastCase) { + notImm2.link(this); + if (!types.second().definitelyIsNumber()) + emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); + emitGetVirtualRegister(op1, regT1); + convertInt32ToDouble(regT1, fpRegT1); + addPtr(tagTypeNumberRegister, regT0); + movePtrToDouble(regT0, fpRegT2); + } else if (op2HasImmediateIntFastCase) { + notImm1.link(this); + if (!types.first().definitelyIsNumber()) + emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); + emitGetVirtualRegister(op2, regT1); + convertInt32ToDouble(regT1, fpRegT1); + addPtr(tagTypeNumberRegister, regT0); + movePtrToDouble(regT0, fpRegT2); + } else { + // if we get here, eax is not an int32, edx not yet checked. + notImm1.link(this); + if (!types.first().definitelyIsNumber()) + emitJumpIfNotImmediateNumber(regT0).linkTo(stubFunctionCall, this); + if (!types.second().definitelyIsNumber()) + emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this); + addPtr(tagTypeNumberRegister, regT0); + movePtrToDouble(regT0, fpRegT1); + Jump op2isDouble = emitJumpIfNotImmediateInteger(regT1); + convertInt32ToDouble(regT1, fpRegT2); + Jump op2wasInteger = jump(); + + // if we get here, eax IS an int32, edx is not. + notImm2.link(this); + if (!types.second().definitelyIsNumber()) + emitJumpIfNotImmediateNumber(regT1).linkTo(stubFunctionCall, this); + convertInt32ToDouble(regT0, fpRegT1); + op2isDouble.link(this); + addPtr(tagTypeNumberRegister, regT1); + movePtrToDouble(regT1, fpRegT2); + op2wasInteger.link(this); + } if (opcodeID == op_add) addDouble(fpRegT2, fpRegT1); else if (opcodeID == op_sub) subDouble(fpRegT2, fpRegT1); - else { - ASSERT(opcodeID == op_mul); + else if (opcodeID == op_mul) mulDouble(fpRegT2, fpRegT1); + else { + ASSERT(opcodeID == op_div); + divDouble(fpRegT2, fpRegT1); } moveDoubleToPtr(fpRegT1, regT0); subPtr(tagTypeNumberRegister, regT0); @@ -2025,16 +2299,14 @@ void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry> unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - if (isOperandConstantImmediateInt(op1) || isOperandConstantImmediateInt(op2)) { - linkSlowCase(iter); - linkSlowCase(iter); - JITStubCall stubCall(this, cti_op_add); - stubCall.addArgument(op1, regT2); - stubCall.addArgument(op2, regT2); - stubCall.call(result); - } else - compileBinaryArithOpSlowCase(op_add, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand)); + if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) + return; + + bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1); + bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2); + compileBinaryArithOpSlowCase(op_add, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand), op1HasImmediateIntFastCase, op2HasImmediateIntFastCase); } void JIT::emit_op_mul(Instruction* currentInstruction) @@ -2069,17 +2341,89 @@ void JIT::emitSlow_op_mul(Instruction* currentInstruction, Vector<SlowCaseEntry> unsigned op2 = currentInstruction[3].u.operand; OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - if ((isOperandConstantImmediateInt(op1) && (getConstantOperandImmediateInt(op1) > 0)) - || (isOperandConstantImmediateInt(op2) && (getConstantOperandImmediateInt(op2) > 0))) { - linkSlowCase(iter); - linkSlowCase(iter); - // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0. - JITStubCall stubCall(this, cti_op_mul); - stubCall.addArgument(op1, regT2); - stubCall.addArgument(op2, regT2); - stubCall.call(result); - } else - compileBinaryArithOpSlowCase(op_mul, iter, result, op1, op2, types); + bool op1HasImmediateIntFastCase = isOperandConstantImmediateInt(op1) && getConstantOperandImmediateInt(op1) > 0; + bool op2HasImmediateIntFastCase = !op1HasImmediateIntFastCase && isOperandConstantImmediateInt(op2) && getConstantOperandImmediateInt(op2) > 0; + compileBinaryArithOpSlowCase(op_mul, iter, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand), op1HasImmediateIntFastCase, op2HasImmediateIntFastCase); +} + +void JIT::emit_op_div(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + if (isOperandConstantImmediateDouble(op1)) { + emitGetVirtualRegister(op1, regT0); + addPtr(tagTypeNumberRegister, regT0); + movePtrToDouble(regT0, fpRegT0); + } else if (isOperandConstantImmediateInt(op1)) { + emitLoadInt32ToDouble(op1, fpRegT0); + } else { + emitGetVirtualRegister(op1, regT0); + if (!types.first().definitelyIsNumber()) + emitJumpSlowCaseIfNotImmediateNumber(regT0); + Jump notInt = emitJumpIfNotImmediateInteger(regT0); + convertInt32ToDouble(regT0, fpRegT0); + Jump skipDoubleLoad = jump(); + notInt.link(this); + addPtr(tagTypeNumberRegister, regT0); + movePtrToDouble(regT0, fpRegT0); + skipDoubleLoad.link(this); + } + + if (isOperandConstantImmediateDouble(op2)) { + emitGetVirtualRegister(op2, regT1); + addPtr(tagTypeNumberRegister, regT1); + movePtrToDouble(regT1, fpRegT1); + } else if (isOperandConstantImmediateInt(op2)) { + emitLoadInt32ToDouble(op2, fpRegT1); + } else { + emitGetVirtualRegister(op2, regT1); + if (!types.second().definitelyIsNumber()) + emitJumpSlowCaseIfNotImmediateNumber(regT1); + Jump notInt = emitJumpIfNotImmediateInteger(regT1); + convertInt32ToDouble(regT1, fpRegT1); + Jump skipDoubleLoad = jump(); + notInt.link(this); + addPtr(tagTypeNumberRegister, regT1); + movePtrToDouble(regT1, fpRegT1); + skipDoubleLoad.link(this); + } + divDouble(fpRegT1, fpRegT0); + + // Double result. + moveDoubleToPtr(fpRegT0, regT0); + subPtr(tagTypeNumberRegister, regT0); + + emitPutVirtualRegister(dst, regT0); +} + +void JIT::emitSlow_op_div(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned result = currentInstruction[1].u.operand; + unsigned op1 = currentInstruction[2].u.operand; + unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + if (types.first().definitelyIsNumber() && types.second().definitelyIsNumber()) { +#ifndef NDEBUG + breakpoint(); +#endif + return; + } + if (!isOperandConstantImmediateDouble(op1) && !isOperandConstantImmediateInt(op1)) { + if (!types.first().definitelyIsNumber()) + linkSlowCase(iter); + } + if (!isOperandConstantImmediateDouble(op2) && !isOperandConstantImmediateInt(op2)) { + if (!types.second().definitelyIsNumber()) + linkSlowCase(iter); + } + // There is an extra slow case for (op1 * -N) or (-N * op2), to check for 0 since this should produce a result of -0. + JITStubCall stubCall(this, cti_op_div); + stubCall.addArgument(op1, regT2); + stubCall.addArgument(op2, regT2); + stubCall.call(result); } void JIT::emit_op_sub(Instruction* currentInstruction) @@ -2090,7 +2434,6 @@ void JIT::emit_op_sub(Instruction* currentInstruction) OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); compileBinaryArithOp(op_sub, result, op1, op2, types); - emitPutVirtualRegister(result); } @@ -2101,7 +2444,7 @@ void JIT::emitSlow_op_sub(Instruction* currentInstruction, Vector<SlowCaseEntry> unsigned op2 = currentInstruction[3].u.operand; OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - compileBinaryArithOpSlowCase(op_sub, iter, result, op1, op2, types); + compileBinaryArithOpSlowCase(op_sub, iter, result, op1, op2, types, false, false); } #else // USE(JSVALUE64) @@ -2284,6 +2627,15 @@ void JIT::emit_op_add(Instruction* currentInstruction) unsigned result = currentInstruction[1].u.operand; unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + + if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) { + JITStubCall stubCall(this, cti_op_add); + stubCall.addArgument(op1, regT2); + stubCall.addArgument(op2, regT2); + stubCall.call(result); + return; + } if (isOperandConstantImmediateInt(op1)) { emitGetVirtualRegister(op2, regT0); @@ -2298,15 +2650,7 @@ void JIT::emit_op_add(Instruction* currentInstruction) signExtend32ToPtr(regT0, regT0); emitPutVirtualRegister(result); } else { - OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); - if (types.first().mightBeNumber() && types.second().mightBeNumber()) - compileBinaryArithOp(op_add, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand)); - else { - JITStubCall stubCall(this, cti_op_add); - stubCall.addArgument(op1, regT2); - stubCall.addArgument(op2, regT2); - stubCall.call(result); - } + compileBinaryArithOp(op_add, result, op1, op2, OperandTypes::fromInt(currentInstruction[4].u.operand)); } } @@ -2316,6 +2660,10 @@ void JIT::emitSlow_op_add(Instruction* currentInstruction, Vector<SlowCaseEntry> unsigned op1 = currentInstruction[2].u.operand; unsigned op2 = currentInstruction[3].u.operand; + OperandTypes types = OperandTypes::fromInt(currentInstruction[4].u.operand); + if (!types.first().mightBeNumber() || !types.second().mightBeNumber()) + return; + if (isOperandConstantImmediateInt(op1)) { Jump notImm = getSlowCase(iter); linkSlowCase(iter); diff --git a/JavaScriptCore/jit/JITCall.cpp b/JavaScriptCore/jit/JITCall.cpp index 7fdb845..179aad7 100644 --- a/JavaScriptCore/jit/JITCall.cpp +++ b/JavaScriptCore/jit/JITCall.cpp @@ -64,10 +64,9 @@ void JIT::compileOpCallSetupArgs(Instruction* instruction) int argCount = instruction[3].u.operand; int registerOffset = instruction[4].u.operand; - emitPutJITStubArg(regT0, 1); - emitPutJITStubArg(regT1, 2); - emitPutJITStubArgConstant(registerOffset, 3); - emitPutJITStubArgConstant(argCount, 5); + emitPutJITStubArg(regT1, regT0, 0); + emitPutJITStubArgConstant(registerOffset, 1); + emitPutJITStubArgConstant(argCount, 2); } void JIT::compileOpConstructSetupArgs(Instruction* instruction) @@ -77,20 +76,18 @@ void JIT::compileOpConstructSetupArgs(Instruction* instruction) int proto = instruction[5].u.operand; int thisRegister = instruction[6].u.operand; - emitPutJITStubArg(regT0, 1); - emitPutJITStubArg(regT1, 2); - emitPutJITStubArgConstant(registerOffset, 3); - emitPutJITStubArgConstant(argCount, 5); - emitPutJITStubArgFromVirtualRegister(proto, 7, regT2, regT3); - emitPutJITStubArgConstant(thisRegister, 9); + emitPutJITStubArg(regT1, regT0, 0); + emitPutJITStubArgConstant(registerOffset, 1); + emitPutJITStubArgConstant(argCount, 2); + emitPutJITStubArgFromVirtualRegister(proto, 3, regT2, regT3); + emitPutJITStubArgConstant(thisRegister, 4); } void JIT::compileOpCallVarargsSetupArgs(Instruction*) { - emitPutJITStubArg(regT0, 1); - emitPutJITStubArg(regT1, 2); - emitPutJITStubArg(regT3, 3); // registerOffset - emitPutJITStubArg(regT2, 5); // argCount + emitPutJITStubArg(regT1, regT0, 0); + emitPutJITStubArg(regT3, 1); // registerOffset + emitPutJITStubArg(regT2, 2); // argCount } void JIT::compileOpCallVarargs(Instruction* instruction) @@ -239,19 +236,17 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned) int argCount = instruction[3].u.operand; int registerOffset = instruction[4].u.operand; - Jump wasEval1; - Jump wasEval2; + Jump wasEval; if (opcodeID == op_call_eval) { JITStubCall stubCall(this, cti_op_call_eval); stubCall.addArgument(callee); stubCall.addArgument(JIT::Imm32(registerOffset)); stubCall.addArgument(JIT::Imm32(argCount)); stubCall.call(); - wasEval1 = branchTest32(NonZero, regT0); - wasEval2 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); + wasEval = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag)); } - emitLoad(callee, regT1, regT2); + emitLoad(callee, regT1, regT0); if (opcodeID == op_call) compileOpCallSetupArgs(instruction); @@ -259,12 +254,12 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned) compileOpConstructSetupArgs(instruction); emitJumpSlowCaseIfNotJSCell(callee, regT1); - addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr))); + addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr))); // First, in the case of a construct, allocate the new object. if (opcodeID == op_construct) { JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); - emitLoad(callee, regT1, regT2); + emitLoad(callee, regT1, regT0); } // Speculatively roll the callframe, assuming argCount will match the arity. @@ -274,12 +269,10 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned) emitNakedCall(m_globalData->jitStubs.ctiVirtualCall()); - if (opcodeID == op_call_eval) { - wasEval1.link(this); - wasEval2.link(this); - } + if (opcodeID == op_call_eval) + wasEval.link(this); - emitStore(dst, regT1, regT0);; + emitStore(dst, regT1, regT0); sampleCodeBlock(m_codeBlock); } @@ -309,22 +302,26 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca int argCount = instruction[3].u.operand; int registerOffset = instruction[4].u.operand; - Jump wasEval1; - Jump wasEval2; + Jump wasEval; if (opcodeID == op_call_eval) { JITStubCall stubCall(this, cti_op_call_eval); stubCall.addArgument(callee); stubCall.addArgument(JIT::Imm32(registerOffset)); stubCall.addArgument(JIT::Imm32(argCount)); stubCall.call(); - wasEval1 = branchTest32(NonZero, regT0); - wasEval2 = branch32(NotEqual, regT1, Imm32(JSValue::CellTag)); + wasEval = branch32(NotEqual, regT1, Imm32(JSValue::EmptyValueTag)); } emitLoad(callee, regT1, regT0); DataLabelPtr addressOfLinkedFunctionCheck; + + BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall); + Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(0)); + + END_UNINTERRUPTED_SEQUENCE(sequenceOpCall); + addSlowCase(jumpToSlow); ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump); m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck; @@ -362,10 +359,8 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca // Call to the callee m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathOther = emitNakedCall(); - if (opcodeID == op_call_eval) { - wasEval1.link(this); - wasEval2.link(this); - } + if (opcodeID == op_call_eval) + wasEval.link(this); // Put the return value in dst. In the interpreter, op_ret does this. emitStore(dst, regT1, regT0); @@ -439,10 +434,10 @@ void JIT::compileOpCallInitializeCallFrame() { store32(regT1, Address(callFrameRegister, RegisterFile::ArgumentCount * static_cast<int>(sizeof(Register)))); - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, RegisterFile::OptionalCalleeArguments * static_cast<int>(sizeof(Register)))); - storePtr(regT2, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register)))); + storePtr(regT0, Address(callFrameRegister, RegisterFile::Callee * static_cast<int>(sizeof(Register)))); storePtr(regT1, Address(callFrameRegister, RegisterFile::ScopeChain * static_cast<int>(sizeof(Register)))); } @@ -452,9 +447,9 @@ void JIT::compileOpCallSetupArgs(Instruction* instruction) int registerOffset = instruction[4].u.operand; // ecx holds func - emitPutJITStubArg(regT2, 1); - emitPutJITStubArgConstant(argCount, 3); - emitPutJITStubArgConstant(registerOffset, 2); + emitPutJITStubArg(regT0, 0); + emitPutJITStubArgConstant(argCount, 2); + emitPutJITStubArgConstant(registerOffset, 1); } void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction) @@ -462,10 +457,10 @@ void JIT::compileOpCallVarargsSetupArgs(Instruction* instruction) int registerOffset = instruction[4].u.operand; // ecx holds func + emitPutJITStubArg(regT0, 0); + emitPutJITStubArg(regT1, 2); + addPtr(Imm32(registerOffset), regT1, regT2); emitPutJITStubArg(regT2, 1); - emitPutJITStubArg(regT1, 3); - addPtr(Imm32(registerOffset), regT1, regT0); - emitPutJITStubArg(regT0, 2); } void JIT::compileOpConstructSetupArgs(Instruction* instruction) @@ -476,11 +471,11 @@ void JIT::compileOpConstructSetupArgs(Instruction* instruction) int thisRegister = instruction[6].u.operand; // ecx holds func - emitPutJITStubArg(regT2, 1); - emitPutJITStubArgConstant(registerOffset, 2); - emitPutJITStubArgConstant(argCount, 3); - emitPutJITStubArgFromVirtualRegister(proto, 4, regT0); - emitPutJITStubArgConstant(thisRegister, 5); + emitPutJITStubArg(regT0, 0); + emitPutJITStubArgConstant(registerOffset, 1); + emitPutJITStubArgConstant(argCount, 2); + emitPutJITStubArgFromVirtualRegister(proto, 3, regT2); + emitPutJITStubArgConstant(thisRegister, 4); } void JIT::compileOpCallVarargs(Instruction* instruction) @@ -490,20 +485,20 @@ void JIT::compileOpCallVarargs(Instruction* instruction) int argCountRegister = instruction[3].u.operand; emitGetVirtualRegister(argCountRegister, regT1); - emitGetVirtualRegister(callee, regT2); + emitGetVirtualRegister(callee, regT0); compileOpCallVarargsSetupArgs(instruction); // Check for JSFunctions. - emitJumpSlowCaseIfNotJSCell(regT2); - addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr))); - + emitJumpSlowCaseIfNotJSCell(regT0); + addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr))); + // Speculatively roll the callframe, assuming argCount will match the arity. - mul32(Imm32(sizeof(Register)), regT0, regT0); + mul32(Imm32(sizeof(Register)), regT2, regT2); intptr_t offset = (intptr_t)sizeof(Register) * (intptr_t)RegisterFile::CallerFrame; - addPtr(Imm32((int32_t)offset), regT0, regT3); + addPtr(Imm32((int32_t)offset), regT2, regT3); addPtr(callFrameRegister, regT3); storePtr(callFrameRegister, regT3); - addPtr(regT0, callFrameRegister); + addPtr(regT2, callFrameRegister); emitNakedCall(m_globalData->jitStubs.ctiVirtualCall()); // Put the return value in dst. In the interpreter, op_ret does this. @@ -539,14 +534,14 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned) Jump wasEval; if (opcodeID == op_call_eval) { JITStubCall stubCall(this, cti_op_call_eval); - stubCall.addArgument(callee, regT2); + stubCall.addArgument(callee, regT0); stubCall.addArgument(JIT::Imm32(registerOffset)); stubCall.addArgument(JIT::Imm32(argCount)); stubCall.call(); wasEval = branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue()))); } - emitGetVirtualRegister(callee, regT2); + emitGetVirtualRegister(callee, regT0); // The arguments have been set up on the hot path for op_call_eval if (opcodeID == op_call) compileOpCallSetupArgs(instruction); @@ -554,13 +549,13 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned) compileOpConstructSetupArgs(instruction); // Check for JSFunctions. - emitJumpSlowCaseIfNotJSCell(regT2); - addSlowCase(branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr))); + emitJumpSlowCaseIfNotJSCell(regT0); + addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr))); // First, in the case of a construct, allocate the new object. if (opcodeID == op_construct) { JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); - emitGetVirtualRegister(callee, regT2); + emitGetVirtualRegister(callee, regT0); } // Speculatively roll the callframe, assuming argCount will match the arity. @@ -606,7 +601,7 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca Jump wasEval; if (opcodeID == op_call_eval) { JITStubCall stubCall(this, cti_op_call_eval); - stubCall.addArgument(callee, regT2); + stubCall.addArgument(callee, regT0); stubCall.addArgument(JIT::Imm32(registerOffset)); stubCall.addArgument(JIT::Imm32(argCount)); stubCall.call(); @@ -615,11 +610,17 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca // This plants a check for a cached JSFunction value, so we can plant a fast link to the callee. // This deliberately leaves the callee in ecx, used when setting up the stack frame below - emitGetVirtualRegister(callee, regT2); + emitGetVirtualRegister(callee, regT0); DataLabelPtr addressOfLinkedFunctionCheck; - Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT2, addressOfLinkedFunctionCheck, ImmPtr(JSValue::encode(JSValue()))); + + BEGIN_UNINTERRUPTED_SEQUENCE(sequenceOpCall); + + Jump jumpToSlow = branchPtrWithPatch(NotEqual, regT0, addressOfLinkedFunctionCheck, ImmPtr(JSValue::encode(JSValue()))); + + END_UNINTERRUPTED_SEQUENCE(sequenceOpCall); + addSlowCase(jumpToSlow); - ASSERT(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow) == patchOffsetOpCallCompareToJump); + ASSERT_JIT_OFFSET(differenceBetween(addressOfLinkedFunctionCheck, jumpToSlow), patchOffsetOpCallCompareToJump); m_callStructureStubCompilationInfo[callLinkInfoIndex].hotPathBegin = addressOfLinkedFunctionCheck; // The following is the fast case, only used whan a callee can be linked. @@ -629,18 +630,18 @@ void JIT::compileOpCall(OpcodeID opcodeID, Instruction* instruction, unsigned ca int proto = instruction[5].u.operand; int thisRegister = instruction[6].u.operand; - emitPutJITStubArg(regT2, 1); - emitPutJITStubArgFromVirtualRegister(proto, 4, regT0); + emitPutJITStubArg(regT0, 0); + emitPutJITStubArgFromVirtualRegister(proto, 3, regT2); JITStubCall stubCall(this, cti_op_construct_JSConstruct); stubCall.call(thisRegister); - emitGetVirtualRegister(callee, regT2); + emitGetVirtualRegister(callee, regT0); } // Fast version of stack frame initialization, directly relative to edi. // Note that this omits to set up RegisterFile::CodeBlock, which is set in the callee storePtr(ImmPtr(JSValue::encode(JSValue())), Address(callFrameRegister, (registerOffset + RegisterFile::OptionalCalleeArguments) * static_cast<int>(sizeof(Register)))); - storePtr(regT2, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register)))); - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain + storePtr(regT0, Address(callFrameRegister, (registerOffset + RegisterFile::Callee) * static_cast<int>(sizeof(Register)))); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_data) + OBJECT_OFFSETOF(ScopeChain, m_node)), regT1); // newScopeChain store32(Imm32(argCount), Address(callFrameRegister, (registerOffset + RegisterFile::ArgumentCount) * static_cast<int>(sizeof(Register)))); storePtr(callFrameRegister, Address(callFrameRegister, (registerOffset + RegisterFile::CallerFrame) * static_cast<int>(sizeof(Register)))); storePtr(regT1, Address(callFrameRegister, (registerOffset + RegisterFile::ScopeChain) * static_cast<int>(sizeof(Register)))); @@ -674,13 +675,13 @@ void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>: compileOpConstructSetupArgs(instruction); // Fast check for JS function. - Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT2); - Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT2), ImmPtr(m_globalData->jsFunctionVPtr)); + Jump callLinkFailNotObject = emitJumpIfNotJSCell(regT0); + Jump callLinkFailNotJSFunction = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsFunctionVPtr)); // First, in the case of a construct, allocate the new object. if (opcodeID == op_construct) { JITStubCall(this, cti_op_construct_JSConstruct).call(registerOffset - RegisterFile::CallFrameHeaderSize - argCount); - emitGetVirtualRegister(callee, regT2); + emitGetVirtualRegister(callee, regT0); } // Speculatively roll the callframe, assuming argCount will match the arity. @@ -688,6 +689,8 @@ void JIT::compileOpCallSlowCase(Instruction* instruction, Vector<SlowCaseEntry>: addPtr(Imm32(registerOffset * static_cast<int>(sizeof(Register))), callFrameRegister); move(Imm32(argCount), regT1); + move(regT0, regT2); + m_callStructureStubCompilationInfo[callLinkInfoIndex].callReturnLocation = emitNakedCall(m_globalData->jitStubs.ctiVirtualCallLink()); // Put the return value in dst. diff --git a/JavaScriptCore/jit/JITInlineMethods.h b/JavaScriptCore/jit/JITInlineMethods.h index b5aaafc..1ce6889 100644 --- a/JavaScriptCore/jit/JITInlineMethods.h +++ b/JavaScriptCore/jit/JITInlineMethods.h @@ -37,28 +37,37 @@ namespace JSC { // puts an arg onto the stack, as an arg to a context threaded function. ALWAYS_INLINE void JIT::emitPutJITStubArg(RegisterID src, unsigned argumentNumber) { - poke(src, argumentNumber); + unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX; + poke(src, argumentStackOffset); } /* Deprecated: Please use JITStubCall instead. */ ALWAYS_INLINE void JIT::emitPutJITStubArgConstant(unsigned value, unsigned argumentNumber) { - poke(Imm32(value), argumentNumber); + unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX; + poke(Imm32(value), argumentStackOffset); } /* Deprecated: Please use JITStubCall instead. */ ALWAYS_INLINE void JIT::emitPutJITStubArgConstant(void* value, unsigned argumentNumber) { - poke(ImmPtr(value), argumentNumber); + unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX; + poke(ImmPtr(value), argumentStackOffset); } /* Deprecated: Please use JITStubCall instead. */ ALWAYS_INLINE void JIT::emitGetJITStubArg(unsigned argumentNumber, RegisterID dst) { - peek(dst, argumentNumber); + unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX; + peek(dst, argumentStackOffset); +} + +ALWAYS_INLINE bool JIT::isOperandConstantImmediateDouble(unsigned src) +{ + return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isDouble(); } ALWAYS_INLINE JSValue JIT::getConstantOperand(unsigned src) @@ -102,38 +111,71 @@ ALWAYS_INLINE JIT::Call JIT::emitNakedCall(CodePtr function) return nakedCall; } -#if PLATFORM(X86) || PLATFORM(X86_64) || (PLATFORM(ARM) && !PLATFORM_ARM_ARCH(7)) +#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL + +ALWAYS_INLINE void JIT::beginUninterruptedSequence(int insnSpace, int constSpace) +{ +#if PLATFORM(ARM_TRADITIONAL) +#ifndef NDEBUG + // Ensure the label after the sequence can also fit + insnSpace += sizeof(ARMWord); + constSpace += sizeof(uint64_t); +#endif + + ensureSpace(insnSpace, constSpace); + +#endif + +#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL +#ifndef NDEBUG + m_uninterruptedInstructionSequenceBegin = label(); + m_uninterruptedConstantSequenceBegin = sizeOfConstantPool(); +#endif +#endif +} + +ALWAYS_INLINE void JIT::endUninterruptedSequence(int insnSpace, int constSpace) +{ +#if defined(ASSEMBLER_HAS_CONSTANT_POOL) && ASSEMBLER_HAS_CONSTANT_POOL + ASSERT(differenceBetween(m_uninterruptedInstructionSequenceBegin, label()) == insnSpace); + ASSERT(sizeOfConstantPool() - m_uninterruptedConstantSequenceBegin == constSpace); +#endif +} + +#endif + +#if PLATFORM(ARM) ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) { - pop(reg); + move(linkRegister, reg); } ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) { - push(reg); + move(reg, linkRegister); } ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) { - push(address); + loadPtr(address, linkRegister); } -#elif PLATFORM_ARM_ARCH(7) +#else // PLATFORM(X86) || PLATFORM(X86_64) ALWAYS_INLINE void JIT::preserveReturnAddressAfterCall(RegisterID reg) { - move(linkRegister, reg); + pop(reg); } ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(RegisterID reg) { - move(reg, linkRegister); + push(reg); } ALWAYS_INLINE void JIT::restoreReturnAddressBeforeReturn(Address address) { - loadPtr(address, linkRegister); + push(address); } #endif @@ -149,16 +191,13 @@ ALWAYS_INLINE void JIT::restoreArgumentReference() { move(stackPointerRegister, firstArgumentRegister); poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); -#if PLATFORM(ARM) && !PLATFORM_ARM_ARCH(7) - move(ctiReturnRegister, ARM::lr); -#endif } ALWAYS_INLINE void JIT::restoreArgumentReferenceForTrampoline() { #if PLATFORM(X86) // Within a trampoline the return address will be on the stack at this point. addPtr(Imm32(sizeof(void*)), stackPointerRegister, firstArgumentRegister); -#elif PLATFORM_ARM_ARCH(7) +#elif PLATFORM(ARM) move(stackPointerRegister, firstArgumentRegister); #endif // In the trampoline on x86-64, the first argument register is not overwritten. @@ -242,8 +281,8 @@ ALWAYS_INLINE void JIT::emitCount(AbstractSamplingCounter& counter, uint32_t cou #if PLATFORM(X86_64) ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction) { - move(ImmPtr(m_interpreter->sampler()->sampleSlot()), X86::ecx); - storePtr(ImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86::ecx); + move(ImmPtr(m_interpreter->sampler()->sampleSlot()), X86Registers::ecx); + storePtr(ImmPtr(m_interpreter->sampler()->encodeSample(instruction, inHostFunction)), X86Registers::ecx); } #else ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostFunction) @@ -257,8 +296,8 @@ ALWAYS_INLINE void JIT::sampleInstruction(Instruction* instruction, bool inHostF #if PLATFORM(X86_64) ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock) { - move(ImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86::ecx); - storePtr(ImmPtr(codeBlock), X86::ecx); + move(ImmPtr(m_interpreter->sampler()->codeBlockSlot()), X86Registers::ecx); + storePtr(ImmPtr(codeBlock), X86Registers::ecx); } #else ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock) @@ -268,6 +307,11 @@ ALWAYS_INLINE void JIT::sampleCodeBlock(CodeBlock* codeBlock) #endif #endif +inline JIT::Address JIT::addressFor(unsigned index, RegisterID base) +{ + return Address(base, (index * sizeof(Register))); +} + #if USE(JSVALUE32_64) inline JIT::Address JIT::tagFor(unsigned index, RegisterID base) @@ -280,11 +324,6 @@ inline JIT::Address JIT::payloadFor(unsigned index, RegisterID base) return Address(base, (index * sizeof(Register)) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)); } -inline JIT::Address JIT::addressFor(unsigned index, RegisterID base) -{ - return Address(base, (index * sizeof(Register))); -} - inline void JIT::emitLoadTag(unsigned index, RegisterID tag) { RegisterID mappedTag; @@ -542,23 +581,28 @@ ALWAYS_INLINE bool JIT::getOperandConstantImmediateInt(unsigned op1, unsigned op return false; } -ALWAYS_INLINE bool JIT::isOperandConstantImmediateDouble(unsigned src) +/* Deprecated: Please use JITStubCall instead. */ + +ALWAYS_INLINE void JIT::emitPutJITStubArg(RegisterID tag, RegisterID payload, unsigned argumentNumber) { - return m_codeBlock->isConstantRegisterIndex(src) && getConstantOperand(src).isDouble(); + unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX; + poke(payload, argumentStackOffset); + poke(tag, argumentStackOffset + 1); } /* Deprecated: Please use JITStubCall instead. */ ALWAYS_INLINE void JIT::emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch1, RegisterID scratch2) { + unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX; if (m_codeBlock->isConstantRegisterIndex(src)) { JSValue constant = m_codeBlock->getConstant(src); - poke(Imm32(constant.payload()), argumentNumber); - poke(Imm32(constant.tag()), argumentNumber + 1); + poke(Imm32(constant.payload()), argumentStackOffset); + poke(Imm32(constant.tag()), argumentStackOffset + 1); } else { emitLoad(src, scratch1, scratch2); - poke(scratch2, argumentNumber); - poke(scratch1, argumentNumber + 1); + poke(scratch2, argumentStackOffset); + poke(scratch1, argumentStackOffset + 1); } } @@ -685,6 +729,24 @@ ALWAYS_INLINE JIT::Jump JIT::emitJumpIfNotImmediateNumber(RegisterID reg) { return branchTestPtr(Zero, reg, tagTypeNumberRegister); } + +inline void JIT::emitLoadDouble(unsigned index, FPRegisterID value) +{ + if (m_codeBlock->isConstantRegisterIndex(index)) { + Register& inConstantPool = m_codeBlock->constantRegister(index); + loadDouble(&inConstantPool, value); + } else + loadDouble(addressFor(index), value); +} + +inline void JIT::emitLoadInt32ToDouble(unsigned index, FPRegisterID value) +{ + if (m_codeBlock->isConstantRegisterIndex(index)) { + Register& inConstantPool = m_codeBlock->constantRegister(index); + convertInt32ToDouble(AbsoluteAddress(&inConstantPool), value); + } else + convertInt32ToDouble(addressFor(index), value); +} #endif ALWAYS_INLINE JIT::Jump JIT::emitJumpIfImmediateInteger(RegisterID reg) @@ -722,6 +784,11 @@ ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateIntegers(RegisterID reg1, addSlowCase(emitJumpIfNotImmediateIntegers(reg1, reg2, scratch)); } +ALWAYS_INLINE void JIT::emitJumpSlowCaseIfNotImmediateNumber(RegisterID reg) +{ + addSlowCase(emitJumpIfNotImmediateNumber(reg)); +} + #if !USE(JSVALUE64) ALWAYS_INLINE void JIT::emitFastArithDeTagImmediate(RegisterID reg) { @@ -750,7 +817,7 @@ ALWAYS_INLINE void JIT::emitFastArithImmToInt(RegisterID reg) #if USE(JSVALUE64) UNUSED_PARAM(reg); #else - rshiftPtr(Imm32(JSImmediate::IntegerPayloadShift), reg); + rshift32(Imm32(JSImmediate::IntegerPayloadShift), reg); #endif } @@ -779,12 +846,13 @@ ALWAYS_INLINE void JIT::emitTagAsBoolImmediate(RegisterID reg) // get arg puts an arg from the SF register array onto the stack, as an arg to a context threaded function. ALWAYS_INLINE void JIT::emitPutJITStubArgFromVirtualRegister(unsigned src, unsigned argumentNumber, RegisterID scratch) { + unsigned argumentStackOffset = (argumentNumber * (sizeof(JSValue) / sizeof(void*))) + JITSTACKFRAME_ARGS_INDEX; if (m_codeBlock->isConstantRegisterIndex(src)) { JSValue value = m_codeBlock->getConstant(src); - emitPutJITStubArgConstant(JSValue::encode(value), argumentNumber); + poke(ImmPtr(JSValue::encode(value)), argumentStackOffset); } else { loadPtr(Address(callFrameRegister, src * sizeof(Register)), scratch); - emitPutJITStubArg(scratch, argumentNumber); + poke(scratch, argumentStackOffset); } killLastResultRegister(); diff --git a/JavaScriptCore/jit/JITOpcodes.cpp b/JavaScriptCore/jit/JITOpcodes.cpp index 13fc981..77fec28 100644 --- a/JavaScriptCore/jit/JITOpcodes.cpp +++ b/JavaScriptCore/jit/JITOpcodes.cpp @@ -33,6 +33,7 @@ #include "JSArray.h" #include "JSCell.h" #include "JSFunction.h" +#include "JSPropertyNameIterator.h" #include "LinkBuffer.h" namespace JSC { @@ -51,8 +52,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)); // Checks out okay! - get the length from the Ustring. - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSString, m_value) + OBJECT_OFFSETOF(UString, m_rep)), regT2); - load32(Address(regT2, OBJECT_OFFSETOF(UString::Rep, len)), regT2); + load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT2); Jump string_failureCases3 = branch32(Above, regT2, Imm32(INT_MAX)); move(regT2, regT0); @@ -64,93 +64,80 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable // (2) Trampolines for the slow cases of op_call / op_call_eval / op_construct. #if ENABLE(JIT_OPTIMIZE_CALL) - /* VirtualCallLink Trampoline */ + // VirtualCallLink Trampoline + // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. Label virtualCallLinkBegin = align(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); - // regT0 holds callee, regT1 holds argCount. - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_body)), regT2); - loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionBodyNode, m_code)), regT2); - Jump hasCodeBlock2 = branchTestPtr(NonZero, regT2); + Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); - // Lazily generate a CodeBlock. - preserveReturnAddressAfterCall(regT3); // return address + Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + preserveReturnAddressAfterCall(regT3); restoreArgumentReference(); Call callJSFunction2 = call(); - move(regT0, regT2); - emitGetJITStubArg(1, regT0); // callee - emitGetJITStubArg(5, regT1); // argCount - restoreReturnAddressBeforeReturn(regT3); // return address + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); hasCodeBlock2.link(this); - // regT2 holds codeBlock. - Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(CodeBlock, m_codeType)), Imm32(NativeCode)); - // Check argCount matches callee arity. - Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(CodeBlock, m_numParameters)), regT1); + Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); preserveReturnAddressAfterCall(regT3); - emitPutJITStubArg(regT3, 3); // return address - emitPutJITStubArg(regT2, 7); // codeBlock + emitPutJITStubArg(regT3, 1); // return address restoreArgumentReference(); Call callArityCheck2 = call(); move(regT1, callFrameRegister); - emitGetJITStubArg(1, regT0); // callee - emitGetJITStubArg(5, regT1); // argCount - restoreReturnAddressBeforeReturn(regT3); // return address - + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); arityCheckOkay2.link(this); + isNativeFunc2.link(this); compileOpCallInitializeCallFrame(); preserveReturnAddressAfterCall(regT3); - emitPutJITStubArg(regT3, 3); + emitPutJITStubArg(regT3, 1); // return address restoreArgumentReference(); Call callLazyLinkCall = call(); restoreReturnAddressBeforeReturn(regT3); jump(regT0); #endif // ENABLE(JIT_OPTIMIZE_CALL) - /* VirtualCall Trampoline */ + // VirtualCall Trampoline + // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. Label virtualCallBegin = align(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); - // regT0 holds callee, regT1 holds argCount. - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_body)), regT2); - loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionBodyNode, m_code)), regT2); - Jump hasCodeBlock3 = branchTestPtr(NonZero, regT2); + Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); - // Lazily generate a CodeBlock. - preserveReturnAddressAfterCall(regT3); // return address + Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + preserveReturnAddressAfterCall(regT3); restoreArgumentReference(); Call callJSFunction1 = call(); - move(regT0, regT2); - emitGetJITStubArg(1, regT0); // callee - emitGetJITStubArg(5, regT1); // argCount - restoreReturnAddressBeforeReturn(regT3); // return address + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); hasCodeBlock3.link(this); - // regT2 holds codeBlock. - Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(CodeBlock, m_codeType)), Imm32(NativeCode)); - - // Check argCount matches callee. - Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(CodeBlock, m_numParameters)), regT1); + // Check argCount matches callee arity. + Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); preserveReturnAddressAfterCall(regT3); - emitPutJITStubArg(regT3, 3); // return address - emitPutJITStubArg(regT2, 7); // codeBlock + emitPutJITStubArg(regT3, 1); // return address restoreArgumentReference(); Call callArityCheck1 = call(); move(regT1, callFrameRegister); - emitGetJITStubArg(1, regT0); // callee - emitGetJITStubArg(5, regT1); // argCount - restoreReturnAddressBeforeReturn(regT3); // return address - + emitGetJITStubArg(2, regT1); // argCount + restoreReturnAddressBeforeReturn(regT3); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); arityCheckOkay3.link(this); + isNativeFunc3.link(this); + compileOpCallInitializeCallFrame(); - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_body)), regT0); - loadPtr(Address(regT0, OBJECT_OFFSETOF(FunctionBodyNode, m_jitCode)), regT0); + loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCode)), regT0); jump(regT0); -#if PLATFORM(X86) +#if PLATFORM(X86) || PLATFORM(ARM_TRADITIONAL) Label nativeCallThunk = align(); preserveReturnAddressAfterCall(regT0); emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address @@ -161,6 +148,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable emitGetFromCallFrameHeaderPtr(RegisterFile::ScopeChain, regT1, regT1); emitPutToCallFrameHeader(regT1, RegisterFile::ScopeChain); +#if PLATFORM(X86) emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); /* We have two structs that we use to describe the stackframe we set up for our @@ -237,34 +225,92 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable #if COMPILER(MSVC) || PLATFORM(LINUX) // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) - addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86::ecx); + addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx); // Plant callee - emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86::eax); - storePtr(X86::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee))); + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax); + storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee))); // Plant callframe - move(callFrameRegister, X86::edx); + move(callFrameRegister, X86Registers::edx); - call(Address(X86::eax, OBJECT_OFFSETOF(JSFunction, m_data))); + call(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_data))); // JSValue is a non-POD type, so eax points to it - emitLoad(0, regT1, regT0, X86::eax); + emitLoad(0, regT1, regT0, X86Registers::eax); #else - emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86::edx); // callee - move(callFrameRegister, X86::ecx); // callFrame - call(Address(X86::edx, OBJECT_OFFSETOF(JSFunction, m_data))); + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx); // callee + move(callFrameRegister, X86Registers::ecx); // callFrame + call(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_data))); #endif // We've put a few temporaries on the stack in addition to the actual arguments // so pull them off now addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister); +#elif PLATFORM(ARM_TRADITIONAL) + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); + + // Allocate stack space for our arglist + COMPILE_ASSERT((sizeof(ArgList) & 0x7) == 0 && sizeof(JSValue) == 8 && sizeof(Register) == 8, ArgList_should_by_8byte_aligned); + subPtr(Imm32(sizeof(ArgList)), stackPointerRegister); + + // Set up arguments + subPtr(Imm32(1), regT0); // Don't include 'this' in argcount + + // Push argcount + storePtr(regT0, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount))); + + // Calculate the start of the callframe header, and store in regT1 + move(callFrameRegister, regT1); + sub32(Imm32(RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), regT1); + + // Calculate start of arguments as callframe header - sizeof(Register) * argcount (regT1) + mul32(Imm32(sizeof(Register)), regT0, regT0); + subPtr(regT0, regT1); + + // push pointer to arguments + storePtr(regT1, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args))); + + // Argument passing method: + // r0 - points to return value + // r1 - callFrame + // r2 - callee + // stack: this(JSValue) and a pointer to ArgList + + move(stackPointerRegister, regT3); + subPtr(Imm32(8), stackPointerRegister); + move(stackPointerRegister, regT0); + subPtr(Imm32(8 + 4 + 4 /* padding */), stackPointerRegister); + + // Setup arg4: + storePtr(regT3, Address(stackPointerRegister, 8)); + + // Setup arg3 + // regT1 currently points to the first argument, regT1-sizeof(Register) points to 'this' + load32(Address(regT1, -(int32_t)sizeof(void*) * 2), regT3); + storePtr(regT3, Address(stackPointerRegister, 0)); + load32(Address(regT1, -(int32_t)sizeof(void*)), regT3); + storePtr(regT3, Address(stackPointerRegister, 4)); + + // Setup arg2: + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, regT2); + + // Setup arg1: + move(callFrameRegister, regT1); + + call(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_data))); + + // Load return value + load32(Address(stackPointerRegister, 16), regT0); + load32(Address(stackPointerRegister, 20), regT1); + + addPtr(Imm32(sizeof(ArgList) + 16 + 8), stackPointerRegister); +#endif + // Check for an exception - // FIXME: Maybe we can optimize this comparison to JSValue(). move(ImmPtr(&globalData->exception), regT2); - Jump sawException1 = branch32(NotEqual, tagFor(0, regT2), Imm32(JSValue::CellTag)); - Jump sawException2 = branch32(NonZero, payloadFor(0, regT2), Imm32(0)); + Jump sawException = branch32(NotEqual, tagFor(0, regT2), Imm32(JSValue::EmptyValueTag)); // Grab the return address. emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT3); @@ -277,13 +323,12 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable ret(); // Handle an exception - sawException1.link(this); - sawException2.link(this); + sawException.link(this); // Grab the return address. emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); move(ImmPtr(&globalData->exceptionLocation), regT2); storePtr(regT1, regT2); - move(ImmPtr(reinterpret_cast<void*>(ctiVMThrowTrampoline)), regT2); + move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT2); emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); restoreReturnAddressBeforeReturn(regT2); @@ -361,14 +406,14 @@ void JIT::emit_op_end(Instruction* currentInstruction) void JIT::emit_op_jmp(Instruction* currentInstruction) { unsigned target = currentInstruction[1].u.operand; - addJump(jump(), target + 1); + addJump(jump(), target); } void JIT::emit_op_loop(Instruction* currentInstruction) { unsigned target = currentInstruction[1].u.operand; emitTimeoutCheck(); - addJump(jump(), target + 1); + addJump(jump(), target); } void JIT::emit_op_loop_if_less(Instruction* currentInstruction) @@ -382,21 +427,21 @@ void JIT::emit_op_loop_if_less(Instruction* currentInstruction) if (isOperandConstantImmediateInt(op1)) { emitLoad(op2, regT1, regT0); addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThan, regT0, Imm32(getConstantOperand(op1).asInt32())), target + 3); + addJump(branch32(GreaterThan, regT0, Imm32(getConstantOperand(op1).asInt32())), target); return; } if (isOperandConstantImmediateInt(op2)) { emitLoad(op1, regT1, regT0); addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target + 3); + addJump(branch32(LessThan, regT0, Imm32(getConstantOperand(op2).asInt32())), target); return; } emitLoad2(op1, regT1, regT0, op2, regT3, regT2); addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThan, regT0, regT2), target + 3); + addJump(branch32(LessThan, regT0, regT2), target); } void JIT::emitSlow_op_loop_if_less(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -409,11 +454,11 @@ void JIT::emitSlow_op_loop_if_less(Instruction* currentInstruction, Vector<SlowC linkSlowCase(iter); // int32 check linkSlowCase(iter); // int32 check - JITStubCall stubCall(this, cti_op_loop_if_less); + JITStubCall stubCall(this, cti_op_jless); stubCall.addArgument(op1); stubCall.addArgument(op2); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction) @@ -427,21 +472,21 @@ void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction) if (isOperandConstantImmediateInt(op1)) { emitLoad(op2, regT1, regT0); addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op1).asInt32())), target + 3); + addJump(branch32(GreaterThanOrEqual, regT0, Imm32(getConstantOperand(op1).asInt32())), target); return; } if (isOperandConstantImmediateInt(op2)) { emitLoad(op1, regT1, regT0); addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target + 3); + addJump(branch32(LessThanOrEqual, regT0, Imm32(getConstantOperand(op2).asInt32())), target); return; } emitLoad2(op1, regT1, regT0, op2, regT3, regT2); addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag))); addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); - addJump(branch32(LessThanOrEqual, regT0, regT2), target + 3); + addJump(branch32(LessThanOrEqual, regT0, regT2), target); } void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -458,7 +503,7 @@ void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<Slo stubCall.addArgument(op1); stubCall.addArgument(op2); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } void JIT::emit_op_new_object(Instruction* currentInstruction) @@ -473,30 +518,20 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) unsigned baseVal = currentInstruction[3].u.operand; unsigned proto = currentInstruction[4].u.operand; - // Load the operands (baseVal, proto, and value respectively) into registers. + // Load the operands into registers. // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result. - emitLoadPayload(proto, regT1); - emitLoadPayload(baseVal, regT0); emitLoadPayload(value, regT2); + emitLoadPayload(baseVal, regT0); + emitLoadPayload(proto, regT1); - // Check that baseVal & proto are cells. - emitJumpSlowCaseIfNotJSCell(proto); + // Check that value, baseVal, and proto are cells. + emitJumpSlowCaseIfNotJSCell(value); emitJumpSlowCaseIfNotJSCell(baseVal); + emitJumpSlowCaseIfNotJSCell(proto); - // Check that baseVal is an object, that it 'ImplementsHasInstance' but that it does not 'OverridesHasInstance'. + // Check that baseVal 'ImplementsDefaultHasInstance'. loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); - addSlowCase(branch32(NotEqual, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); // FIXME: Maybe remove this test. - addSlowCase(branchTest32(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsHasInstance))); // FIXME: TOT checks ImplementsDefaultHasInstance. - - // If value is not an Object, return false. - emitLoadTag(value, regT0); - Jump valueIsImmediate = branch32(NotEqual, regT0, Imm32(JSValue::CellTag)); - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); - Jump valueIsNotObject = branch32(NotEqual, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)); // FIXME: Maybe remove this test. - - // Check proto is object. - loadPtr(Address(regT1, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); - addSlowCase(branch32(NotEqual, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); + addSlowCase(branchTest32(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsDefaultHasInstance))); // Optimistically load the result true, and start looping. // Initially, regT1 still contains proto and regT2 still contains value. @@ -504,16 +539,14 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) move(Imm32(JSValue::TrueTag), regT0); Label loop(this); - // Load the prototype of the object in regT2. If this is equal to regT1 - WIN! + // Load the prototype of the cell in regT2. If this is equal to regT1 - WIN! // Otherwise, check if we've hit null - if we have then drop out of the loop, if not go again. loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); load32(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); Jump isInstance = branchPtr(Equal, regT2, regT1); - branch32(NotEqual, regT2, Imm32(0), loop); + branchTest32(NonZero, regT2).linkTo(loop, this); // We get here either by dropping out of the loop, or if value was not an Object. Result is false. - valueIsImmediate.link(this); - valueIsNotObject.link(this); move(Imm32(JSValue::FalseTag), regT0); // isInstance jumps right down to here, to skip setting the result to false (it has already set true). @@ -528,11 +561,10 @@ void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCas unsigned baseVal = currentInstruction[3].u.operand; unsigned proto = currentInstruction[4].u.operand; + linkSlowCaseIfNotJSCell(iter, value); linkSlowCaseIfNotJSCell(iter, baseVal); linkSlowCaseIfNotJSCell(iter, proto); linkSlowCase(iter); - linkSlowCase(iter); - linkSlowCase(iter); JITStubCall stubCall(this, cti_op_instanceof); stubCall.addArgument(value); @@ -544,7 +576,7 @@ void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCas void JIT::emit_op_new_func(Instruction* currentInstruction) { JITStubCall stubCall(this, cti_op_new_func); - stubCall.addArgument(ImmPtr(m_codeBlock->function(currentInstruction[2].u.operand))); + stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand))); stubCall.call(currentInstruction[1].u.operand); } @@ -687,12 +719,12 @@ void JIT::emit_op_loop_if_true(Instruction* currentInstruction) emitLoad(cond, regT1, regT0); Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); - addJump(branch32(NotEqual, regT0, Imm32(0)), target + 2); + addJump(branch32(NotEqual, regT0, Imm32(0)), target); Jump isNotZero = jump(); isNotInteger.link(this); - addJump(branch32(Equal, regT1, Imm32(JSValue::TrueTag)), target + 2); + addJump(branch32(Equal, regT1, Imm32(JSValue::TrueTag)), target); addSlowCase(branch32(NotEqual, regT1, Imm32(JSValue::FalseTag))); isNotZero.link(this); @@ -708,7 +740,51 @@ void JIT::emitSlow_op_loop_if_true(Instruction* currentInstruction, Vector<SlowC JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(cond); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 2); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); +} + +void JIT::emit_op_loop_if_false(Instruction* currentInstruction) +{ + unsigned cond = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + emitTimeoutCheck(); + + emitLoad(cond, regT1, regT0); + + Jump isTrue = branch32(Equal, regT1, Imm32(JSValue::TrueTag)); + addJump(branch32(Equal, regT1, Imm32(JSValue::FalseTag)), target); + + Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); + Jump isTrue2 = branch32(NotEqual, regT0, Imm32(0)); + addJump(jump(), target); + + if (supportsFloatingPoint()) { + isNotInteger.link(this); + + addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + + zeroDouble(fpRegT0); + emitLoadDouble(cond, fpRegT1); + addJump(branchDouble(DoubleEqualOrUnordered, fpRegT0, fpRegT1), target); + } else + addSlowCase(isNotInteger); + + isTrue.link(this); + isTrue2.link(this); +} + +void JIT::emitSlow_op_loop_if_false(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned cond = currentInstruction[1].u.operand; + unsigned target = currentInstruction[2].u.operand; + + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_jtrue); + stubCall.addArgument(cond); + stubCall.call(); + emitJumpSlowToHot(branchTest32(Zero, regT0), target); } void JIT::emit_op_resolve_base(Instruction* currentInstruction) @@ -801,20 +877,23 @@ void JIT::emit_op_jfalse(Instruction* currentInstruction) emitLoad(cond, regT1, regT0); Jump isTrue = branch32(Equal, regT1, Imm32(JSValue::TrueTag)); - addJump(branch32(Equal, regT1, Imm32(JSValue::FalseTag)), target + 2); + addJump(branch32(Equal, regT1, Imm32(JSValue::FalseTag)), target); Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); Jump isTrue2 = branch32(NotEqual, regT0, Imm32(0)); - addJump(jump(), target + 2); + addJump(jump(), target); - isNotInteger.link(this); + if (supportsFloatingPoint()) { + isNotInteger.link(this); - addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + + zeroDouble(fpRegT0); + emitLoadDouble(cond, fpRegT1); + addJump(branchDouble(DoubleEqualOrUnordered, fpRegT0, fpRegT1), target); + } else + addSlowCase(isNotInteger); - zeroDouble(fpRegT0); - emitLoadDouble(cond, fpRegT1); - addJump(branchDouble(DoubleEqual, fpRegT0, fpRegT1), target + 2); - isTrue.link(this); isTrue2.link(this); } @@ -828,7 +907,7 @@ void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEnt JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(cond); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), target + 2); // Inverted. + emitJumpSlowToHot(branchTest32(Zero, regT0), target); // Inverted. } void JIT::emit_op_jtrue(Instruction* currentInstruction) @@ -839,20 +918,23 @@ void JIT::emit_op_jtrue(Instruction* currentInstruction) emitLoad(cond, regT1, regT0); Jump isFalse = branch32(Equal, regT1, Imm32(JSValue::FalseTag)); - addJump(branch32(Equal, regT1, Imm32(JSValue::TrueTag)), target + 2); + addJump(branch32(Equal, regT1, Imm32(JSValue::TrueTag)), target); Jump isNotInteger = branch32(NotEqual, regT1, Imm32(JSValue::Int32Tag)); Jump isFalse2 = branch32(Equal, regT0, Imm32(0)); - addJump(jump(), target + 2); + addJump(jump(), target); - isNotInteger.link(this); + if (supportsFloatingPoint()) { + isNotInteger.link(this); - addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + addSlowCase(branch32(Above, regT1, Imm32(JSValue::LowestTag))); + + zeroDouble(fpRegT0); + emitLoadDouble(cond, fpRegT1); + addJump(branchDouble(DoubleNotEqual, fpRegT0, fpRegT1), target); + } else + addSlowCase(isNotInteger); - zeroDouble(fpRegT0); - emitLoadDouble(cond, fpRegT1); - addJump(branchDouble(DoubleNotEqual, fpRegT0, fpRegT1), target + 2); - isFalse.link(this); isFalse2.link(this); } @@ -866,7 +948,7 @@ void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntr JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(cond); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 2); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } void JIT::emit_op_jeq_null(Instruction* currentInstruction) @@ -880,7 +962,7 @@ void JIT::emit_op_jeq_null(Instruction* currentInstruction) // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); - addJump(branchTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target + 2); + addJump(branchTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target); Jump wasNotImmediate = jump(); @@ -891,7 +973,7 @@ void JIT::emit_op_jeq_null(Instruction* currentInstruction) set32(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1); or32(regT2, regT1); - addJump(branchTest32(NonZero, regT1), target + 2); + addJump(branchTest32(NonZero, regT1), target); wasNotImmediate.link(this); } @@ -907,7 +989,7 @@ void JIT::emit_op_jneq_null(Instruction* currentInstruction) // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); - addJump(branchTest32(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target + 2); + addJump(branchTest32(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target); Jump wasNotImmediate = jump(); @@ -918,7 +1000,7 @@ void JIT::emit_op_jneq_null(Instruction* currentInstruction) set32(Equal, regT1, Imm32(JSValue::UndefinedTag), regT1); or32(regT2, regT1); - addJump(branchTest32(Zero, regT1), target + 2); + addJump(branchTest32(Zero, regT1), target); wasNotImmediate.link(this); } @@ -930,8 +1012,8 @@ void JIT::emit_op_jneq_ptr(Instruction* currentInstruction) unsigned target = currentInstruction[3].u.operand; emitLoad(src, regT1, regT0); - addJump(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)), target + 3); - addJump(branchPtr(NotEqual, regT0, ImmPtr(ptr)), target + 3); + addJump(branch32(NotEqual, regT1, Imm32(JSValue::CellTag)), target); + addJump(branchPtr(NotEqual, regT0, ImmPtr(ptr)), target); } void JIT::emit_op_jsr(Instruction* currentInstruction) @@ -939,7 +1021,7 @@ void JIT::emit_op_jsr(Instruction* currentInstruction) int retAddrDst = currentInstruction[1].u.operand; int target = currentInstruction[2].u.operand; DataLabelPtr storeLocation = storePtrWithPatch(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst)); - addJump(jump(), target + 2); + addJump(jump(), target); m_jsrSites.append(JSRInfo(storeLocation, label())); } @@ -1180,7 +1262,7 @@ void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) void JIT::emit_op_new_func_exp(Instruction* currentInstruction) { JITStubCall stubCall(this, cti_op_new_func_exp); - stubCall.addArgument(ImmPtr(m_codeBlock->functionExpression(currentInstruction[2].u.operand))); + stubCall.addArgument(ImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand))); stubCall.call(currentInstruction[1].u.operand); } @@ -1205,23 +1287,109 @@ void JIT::emit_op_throw(Instruction* currentInstruction) #endif } +void JIT::emit_op_get_pnames(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int base = currentInstruction[2].u.operand; + int i = currentInstruction[3].u.operand; + int size = currentInstruction[4].u.operand; + int breakTarget = currentInstruction[5].u.operand; + + JumpList isNotObject; + + emitLoad(base, regT1, regT0); + if (!m_codeBlock->isKnownNotImmediate(base)) + isNotObject.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); + if (base != m_codeBlock->thisRegister()) { + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + isNotObject.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); + } + + // We could inline the case where you have a valid cache, but + // this call doesn't seem to be hot. + Label isObject(this); + JITStubCall getPnamesStubCall(this, cti_op_get_pnames); + getPnamesStubCall.addArgument(regT0); + getPnamesStubCall.call(dst); + load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3); + store32(Imm32(0), addressFor(i)); + store32(regT3, addressFor(size)); + Jump end = jump(); + + isNotObject.link(this); + addJump(branch32(Equal, regT1, Imm32(JSValue::NullTag)), breakTarget); + addJump(branch32(Equal, regT1, Imm32(JSValue::UndefinedTag)), breakTarget); + JITStubCall toObjectStubCall(this, cti_to_object); + toObjectStubCall.addArgument(regT1, regT0); + toObjectStubCall.call(base); + jump().linkTo(isObject, this); + + end.link(this); +} + void JIT::emit_op_next_pname(Instruction* currentInstruction) { int dst = currentInstruction[1].u.operand; - int iter = currentInstruction[2].u.operand; - int target = currentInstruction[3].u.operand; + int base = currentInstruction[2].u.operand; + int i = currentInstruction[3].u.operand; + int size = currentInstruction[4].u.operand; + int it = currentInstruction[5].u.operand; + int target = currentInstruction[6].u.operand; + + JumpList callHasProperty; + + Label begin(this); + load32(addressFor(i), regT0); + Jump end = branch32(Equal, regT0, addressFor(size)); + + // Grab key @ i + loadPtr(addressFor(it), regT1); + loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2); + load32(BaseIndex(regT2, regT0, TimesEight), regT2); + store32(Imm32(JSValue::CellTag), tagFor(dst)); + store32(regT2, payloadFor(dst)); + + // Increment i + add32(Imm32(1), regT0); + store32(regT0, addressFor(i)); + + // Verify that i is valid: + loadPtr(addressFor(base), regT0); + + // Test base's structure + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))))); + + // Test base's prototype chain + loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3); + loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3); + addJump(branchTestPtr(Zero, Address(regT3)), target); - load32(Address(callFrameRegister, (iter * sizeof(Register))), regT0); + Label checkPrototype(this); + callHasProperty.append(branch32(Equal, Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.tag)), Imm32(JSValue::NullTag))); + loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype) + OBJECT_OFFSETOF(JSValue, u.asBits.payload)), regT2); + loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3))); + addPtr(Imm32(sizeof(Structure*)), regT3); + branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this); + + // Continue loop. + addJump(jump(), target); - JITStubCall stubCall(this, cti_op_next_pname); + // Slow case: Ask the object if i is valid. + callHasProperty.link(this); + loadPtr(addressFor(dst), regT1); + JITStubCall stubCall(this, cti_has_property); stubCall.addArgument(regT0); + stubCall.addArgument(regT1); stubCall.call(); - Jump endOfIter = branchTestPtr(Zero, regT0); - emitStore(dst, regT1, regT0); - map(m_bytecodeIndex + OPCODE_LENGTH(op_next_pname), dst, regT1, regT0); - addJump(jump(), target + 3); - endOfIter.link(this); + // Test for valid key. + addJump(branchTest32(NonZero, regT0), target); + jump().linkTo(begin, this); + + // End of loop. + end.link(this); } void JIT::emit_op_push_scope(Instruction* currentInstruction) @@ -1244,7 +1412,7 @@ void JIT::emit_op_to_jsnumber(Instruction* currentInstruction) emitLoad(src, regT1, regT0); Jump isInt32 = branch32(Equal, regT1, Imm32(JSValue::Int32Tag)); - addSlowCase(branch32(AboveOrEqual, regT1, Imm32(JSValue::DeletedValueTag))); + addSlowCase(branch32(AboveOrEqual, regT1, Imm32(JSValue::EmptyValueTag))); isInt32.link(this); if (src != dst) @@ -1291,7 +1459,7 @@ void JIT::emit_op_jmp_scopes(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_jmp_scopes); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); stubCall.call(); - addJump(jump(), currentInstruction[2].u.operand + 2); + addJump(jump(), currentInstruction[2].u.operand); } void JIT::emit_op_switch_imm(Instruction* currentInstruction) @@ -1388,8 +1556,7 @@ void JIT::emit_op_enter_with_activation(Instruction* currentInstruction) void JIT::emit_op_create_arguments(Instruction*) { - Jump argsNotCell = branch32(NotEqual, tagFor(RegisterFile::ArgumentsRegister, callFrameRegister), Imm32(JSValue::CellTag)); - Jump argsNotNull = branchTestPtr(NonZero, payloadFor(RegisterFile::ArgumentsRegister, callFrameRegister)); + Jump argsCreated = branch32(NotEqual, tagFor(RegisterFile::ArgumentsRegister, callFrameRegister), Imm32(JSValue::EmptyValueTag)); // If we get here the arguments pointer is a null cell - i.e. arguments need lazy creation. if (m_codeBlock->m_numParameters == 1) @@ -1397,8 +1564,7 @@ void JIT::emit_op_create_arguments(Instruction*) else JITStubCall(this, cti_op_create_arguments).call(); - argsNotCell.link(this); - argsNotNull.link(this); + argsCreated.link(this); } void JIT::emit_op_init_arguments(Instruction*) @@ -1470,8 +1636,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable Jump string_failureCases2 = branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsStringVPtr)); // Checks out okay! - get the length from the Ustring. - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSString, m_value) + OBJECT_OFFSETOF(UString, m_rep)), regT0); - load32(Address(regT0, OBJECT_OFFSETOF(UString::Rep, len)), regT0); + load32(Address(regT0, OBJECT_OFFSETOF(JSString, m_stringLength)), regT0); Jump string_failureCases3 = branch32(Above, regT0, Imm32(JSImmediate::maxImmediateInt)); @@ -1484,85 +1649,77 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable // (3) Trampolines for the slow cases of op_call / op_call_eval / op_construct. COMPILE_ASSERT(sizeof(CodeType) == 4, CodeTypeEnumMustBe32Bit); + // VirtualCallLink Trampoline + // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. Label virtualCallLinkBegin = align(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + + Jump isNativeFunc2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); - // Load the callee CodeBlock* into eax - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_body)), regT3); - loadPtr(Address(regT3, OBJECT_OFFSETOF(FunctionBodyNode, m_code)), regT0); - Jump hasCodeBlock2 = branchTestPtr(NonZero, regT0); + Jump hasCodeBlock2 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); preserveReturnAddressAfterCall(regT3); restoreArgumentReference(); Call callJSFunction2 = call(); - emitGetJITStubArg(1, regT2); - emitGetJITStubArg(3, regT1); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); + emitGetJITStubArg(2, regT1); // argCount restoreReturnAddressBeforeReturn(regT3); hasCodeBlock2.link(this); - Jump isNativeFunc2 = branch32(Equal, Address(regT0, OBJECT_OFFSETOF(CodeBlock, m_codeType)), Imm32(NativeCode)); - // Check argCount matches callee arity. - Jump arityCheckOkay2 = branch32(Equal, Address(regT0, OBJECT_OFFSETOF(CodeBlock, m_numParameters)), regT1); + Jump arityCheckOkay2 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); preserveReturnAddressAfterCall(regT3); - emitPutJITStubArg(regT3, 2); - emitPutJITStubArg(regT0, 4); + emitPutJITStubArg(regT3, 1); // return address restoreArgumentReference(); Call callArityCheck2 = call(); move(regT1, callFrameRegister); - emitGetJITStubArg(1, regT2); - emitGetJITStubArg(3, regT1); + emitGetJITStubArg(2, regT1); // argCount restoreReturnAddressBeforeReturn(regT3); arityCheckOkay2.link(this); + isNativeFunc2.link(this); compileOpCallInitializeCallFrame(); - preserveReturnAddressAfterCall(regT3); - emitPutJITStubArg(regT3, 2); + emitPutJITStubArg(regT3, 1); // return address restoreArgumentReference(); Call callLazyLinkCall = call(); restoreReturnAddressBeforeReturn(regT3); - jump(regT0); + // VirtualCall Trampoline + // regT0 holds callee, regT1 holds argCount. regT2 will hold the FunctionExecutable. Label virtualCallBegin = align(); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); - // Load the callee CodeBlock* into eax - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_body)), regT3); - loadPtr(Address(regT3, OBJECT_OFFSETOF(FunctionBodyNode, m_code)), regT0); - Jump hasCodeBlock3 = branchTestPtr(NonZero, regT0); + Jump isNativeFunc3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); + + Jump hasCodeBlock3 = branch32(GreaterThan, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), Imm32(0)); preserveReturnAddressAfterCall(regT3); restoreArgumentReference(); Call callJSFunction1 = call(); - emitGetJITStubArg(1, regT2); - emitGetJITStubArg(3, regT1); + emitGetJITStubArg(2, regT1); // argCount restoreReturnAddressBeforeReturn(regT3); - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_body)), regT3); // reload the function body nody, so we can reload the code pointer. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); hasCodeBlock3.link(this); - Jump isNativeFunc3 = branch32(Equal, Address(regT0, OBJECT_OFFSETOF(CodeBlock, m_codeType)), Imm32(NativeCode)); - // Check argCount matches callee arity. - Jump arityCheckOkay3 = branch32(Equal, Address(regT0, OBJECT_OFFSETOF(CodeBlock, m_numParameters)), regT1); + Jump arityCheckOkay3 = branch32(Equal, Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_numParameters)), regT1); preserveReturnAddressAfterCall(regT3); - emitPutJITStubArg(regT3, 2); - emitPutJITStubArg(regT0, 4); + emitPutJITStubArg(regT3, 1); // return address restoreArgumentReference(); Call callArityCheck1 = call(); move(regT1, callFrameRegister); - emitGetJITStubArg(1, regT2); - emitGetJITStubArg(3, regT1); + emitGetJITStubArg(2, regT1); // argCount restoreReturnAddressBeforeReturn(regT3); - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSFunction, m_body)), regT3); // reload the function body nody, so we can reload the code pointer. + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSFunction, m_executable)), regT2); arityCheckOkay3.link(this); + isNativeFunc3.link(this); - // load ctiCode from the new codeBlock. - loadPtr(Address(regT3, OBJECT_OFFSETOF(FunctionBodyNode, m_jitCode)), regT0); - compileOpCallInitializeCallFrame(); + loadPtr(Address(regT2, OBJECT_OFFSETOF(FunctionExecutable, m_jitCode)), regT0); jump(regT0); - Label nativeCallThunk = align(); preserveReturnAddressAfterCall(regT0); emitPutToCallFrameHeader(regT0, RegisterFile::ReturnPC); // Push return address @@ -1575,39 +1732,39 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable #if PLATFORM(X86_64) - emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, X86::ecx); + emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, X86Registers::ecx); // Allocate stack space for our arglist subPtr(Imm32(sizeof(ArgList)), stackPointerRegister); COMPILE_ASSERT((sizeof(ArgList) & 0xf) == 0, ArgList_should_by_16byte_aligned); // Set up arguments - subPtr(Imm32(1), X86::ecx); // Don't include 'this' in argcount + subPtr(Imm32(1), X86Registers::ecx); // Don't include 'this' in argcount // Push argcount - storePtr(X86::ecx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount))); + storePtr(X86Registers::ecx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_argCount))); // Calculate the start of the callframe header, and store in edx - addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), callFrameRegister, X86::edx); + addPtr(Imm32(-RegisterFile::CallFrameHeaderSize * (int32_t)sizeof(Register)), callFrameRegister, X86Registers::edx); // Calculate start of arguments as callframe header - sizeof(Register) * argcount (ecx) - mul32(Imm32(sizeof(Register)), X86::ecx, X86::ecx); - subPtr(X86::ecx, X86::edx); + mul32(Imm32(sizeof(Register)), X86Registers::ecx, X86Registers::ecx); + subPtr(X86Registers::ecx, X86Registers::edx); // push pointer to arguments - storePtr(X86::edx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args))); + storePtr(X86Registers::edx, Address(stackPointerRegister, OBJECT_OFFSETOF(ArgList, m_args))); // ArgList is passed by reference so is stackPointerRegister - move(stackPointerRegister, X86::ecx); + move(stackPointerRegister, X86Registers::ecx); // edx currently points to the first argument, edx-sizeof(Register) points to 'this' - loadPtr(Address(X86::edx, -(int32_t)sizeof(Register)), X86::edx); + loadPtr(Address(X86Registers::edx, -(int32_t)sizeof(Register)), X86Registers::edx); - emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86::esi); + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::esi); - move(callFrameRegister, X86::edi); + move(callFrameRegister, X86Registers::edi); - call(Address(X86::esi, OBJECT_OFFSETOF(JSFunction, m_data))); + call(Address(X86Registers::esi, OBJECT_OFFSETOF(JSFunction, m_data))); addPtr(Imm32(sizeof(ArgList)), stackPointerRegister); #elif PLATFORM(X86) @@ -1676,33 +1833,33 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable #if COMPILER(MSVC) || PLATFORM(LINUX) // ArgList is passed by reference so is stackPointerRegister + 4 * sizeof(Register) - addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86::ecx); + addPtr(Imm32(OBJECT_OFFSETOF(NativeCallFrameStructure, result)), stackPointerRegister, X86Registers::ecx); // Plant callee - emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86::eax); - storePtr(X86::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee))); + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::eax); + storePtr(X86Registers::eax, Address(stackPointerRegister, OBJECT_OFFSETOF(NativeCallFrameStructure, callee))); // Plant callframe - move(callFrameRegister, X86::edx); + move(callFrameRegister, X86Registers::edx); - call(Address(X86::eax, OBJECT_OFFSETOF(JSFunction, m_data))); + call(Address(X86Registers::eax, OBJECT_OFFSETOF(JSFunction, m_data))); // JSValue is a non-POD type - loadPtr(Address(X86::eax), X86::eax); + loadPtr(Address(X86Registers::eax), X86Registers::eax); #else // Plant callee - emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86::edx); + emitGetFromCallFrameHeaderPtr(RegisterFile::Callee, X86Registers::edx); // Plant callframe - move(callFrameRegister, X86::ecx); - call(Address(X86::edx, OBJECT_OFFSETOF(JSFunction, m_data))); + move(callFrameRegister, X86Registers::ecx); + call(Address(X86Registers::edx, OBJECT_OFFSETOF(JSFunction, m_data))); #endif // We've put a few temporaries on the stack in addition to the actual arguments // so pull them off now addPtr(Imm32(NativeCallFrameSize - sizeof(NativeFunctionCalleeSignature)), stackPointerRegister); -#elif PLATFORM(ARM) && !PLATFORM_ARM_ARCH(7) +#elif PLATFORM(ARM) emitGetFromCallFrameHeader32(RegisterFile::ArgumentCount, regT0); // Allocate stack space for our arglist @@ -1736,9 +1893,8 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable move(callFrameRegister, regT0); // Setup arg4: This is a plain hack - move(stackPointerRegister, ARM::S0); + move(stackPointerRegister, ARMRegisters::r3); - move(ctiReturnRegister, ARM::lr); call(Address(regT1, OBJECT_OFFSETOF(JSFunction, m_data))); addPtr(Imm32(sizeof(ArgList)), stackPointerRegister); @@ -1769,7 +1925,7 @@ void JIT::privateCompileCTIMachineTrampolines(RefPtr<ExecutablePool>* executable emitGetFromCallFrameHeaderPtr(RegisterFile::ReturnPC, regT1); move(ImmPtr(&globalData->exceptionLocation), regT2); storePtr(regT1, regT2); - move(ImmPtr(reinterpret_cast<void*>(ctiVMThrowTrampoline)), regT2); + move(ImmPtr(FunctionPtr(ctiVMThrowTrampoline).value()), regT2); emitGetFromCallFrameHeaderPtr(RegisterFile::CallerFrame, callFrameRegister); poke(callFrameRegister, OBJECT_OFFSETOF(struct JITStackFrame, callFrame) / sizeof (void*)); restoreReturnAddressBeforeReturn(regT2); @@ -1845,8 +2001,8 @@ void JIT::emit_op_end(Instruction* currentInstruction) void JIT::emit_op_jmp(Instruction* currentInstruction) { unsigned target = currentInstruction[1].u.operand; - addJump(jump(), target + 1); - RECORD_JUMP_TARGET(target + 1); + addJump(jump(), target); + RECORD_JUMP_TARGET(target); } void JIT::emit_op_loop(Instruction* currentInstruction) @@ -1854,7 +2010,7 @@ void JIT::emit_op_loop(Instruction* currentInstruction) emitTimeoutCheck(); unsigned target = currentInstruction[1].u.operand; - addJump(jump(), target + 1); + addJump(jump(), target); } void JIT::emit_op_loop_if_less(Instruction* currentInstruction) @@ -1872,7 +2028,7 @@ void JIT::emit_op_loop_if_less(Instruction* currentInstruction) #else int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2))); #endif - addJump(branch32(LessThan, regT0, Imm32(op2imm)), target + 3); + addJump(branch32(LessThan, regT0, Imm32(op2imm)), target); } else if (isOperandConstantImmediateInt(op1)) { emitGetVirtualRegister(op2, regT0); emitJumpSlowCaseIfNotImmediateInteger(regT0); @@ -1881,12 +2037,12 @@ void JIT::emit_op_loop_if_less(Instruction* currentInstruction) #else int32_t op1imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op1))); #endif - addJump(branch32(GreaterThan, regT0, Imm32(op1imm)), target + 3); + addJump(branch32(GreaterThan, regT0, Imm32(op1imm)), target); } else { emitGetVirtualRegisters(op1, regT0, op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); - addJump(branch32(LessThan, regT0, regT1), target + 3); + addJump(branch32(LessThan, regT0, regT1), target); } } @@ -1905,12 +2061,12 @@ void JIT::emit_op_loop_if_lesseq(Instruction* currentInstruction) #else int32_t op2imm = static_cast<int32_t>(JSImmediate::rawValue(getConstantOperand(op2))); #endif - addJump(branch32(LessThanOrEqual, regT0, Imm32(op2imm)), target + 3); + addJump(branch32(LessThanOrEqual, regT0, Imm32(op2imm)), target); } else { emitGetVirtualRegisters(op1, regT0, op2, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT0); emitJumpSlowCaseIfNotImmediateInteger(regT1); - addJump(branch32(LessThanOrEqual, regT0, regT1), target + 3); + addJump(branch32(LessThanOrEqual, regT0, regT1), target); } } @@ -1921,30 +2077,26 @@ void JIT::emit_op_new_object(Instruction* currentInstruction) void JIT::emit_op_instanceof(Instruction* currentInstruction) { + unsigned dst = currentInstruction[1].u.operand; + unsigned value = currentInstruction[2].u.operand; + unsigned baseVal = currentInstruction[3].u.operand; + unsigned proto = currentInstruction[4].u.operand; + // Load the operands (baseVal, proto, and value respectively) into registers. // We use regT0 for baseVal since we will be done with this first, and we can then use it for the result. - emitGetVirtualRegister(currentInstruction[3].u.operand, regT0); - emitGetVirtualRegister(currentInstruction[4].u.operand, regT1); - emitGetVirtualRegister(currentInstruction[2].u.operand, regT2); + emitGetVirtualRegister(value, regT2); + emitGetVirtualRegister(baseVal, regT0); + emitGetVirtualRegister(proto, regT1); // Check that baseVal & proto are cells. - emitJumpSlowCaseIfNotJSCell(regT0); - emitJumpSlowCaseIfNotJSCell(regT1); + emitJumpSlowCaseIfNotJSCell(regT2, value); + emitJumpSlowCaseIfNotJSCell(regT0, baseVal); + emitJumpSlowCaseIfNotJSCell(regT1, proto); - // Check that baseVal is an object, that it 'ImplementsHasInstance' but that it does not 'OverridesHasInstance'. + // Check that baseVal 'ImplementsDefaultHasInstance'. loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); - addSlowCase(branch32(NotEqual, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); addSlowCase(branchTest32(Zero, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(ImplementsDefaultHasInstance))); - // If value is not an Object, return false. - Jump valueIsImmediate = emitJumpIfNotJSCell(regT2); - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); - Jump valueIsNotObject = branch32(NotEqual, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType)); - - // Check proto is object. - loadPtr(Address(regT1, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); - addSlowCase(branch32(NotEqual, Address(regT0, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); - // Optimistically load the result true, and start looping. // Initially, regT1 still contains proto and regT2 still contains value. // As we loop regT2 will be updated with its prototype, recursively walking the prototype chain. @@ -1956,22 +2108,20 @@ void JIT::emit_op_instanceof(Instruction* currentInstruction) loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2); Jump isInstance = branchPtr(Equal, regT2, regT1); - branchPtr(NotEqual, regT2, ImmPtr(JSValue::encode(jsNull())), loop); + emitJumpIfJSCell(regT2).linkTo(loop, this); // We get here either by dropping out of the loop, or if value was not an Object. Result is false. - valueIsImmediate.link(this); - valueIsNotObject.link(this); move(ImmPtr(JSValue::encode(jsBoolean(false))), regT0); // isInstance jumps right down to here, to skip setting the result to false (it has already set true). isInstance.link(this); - emitPutVirtualRegister(currentInstruction[1].u.operand); + emitPutVirtualRegister(dst); } void JIT::emit_op_new_func(Instruction* currentInstruction) { JITStubCall stubCall(this, cti_op_new_func); - stubCall.addArgument(ImmPtr(m_codeBlock->function(currentInstruction[2].u.operand))); + stubCall.addArgument(ImmPtr(m_codeBlock->functionDecl(currentInstruction[2].u.operand))); stubCall.call(currentInstruction[1].u.operand); } @@ -2142,13 +2292,32 @@ void JIT::emit_op_loop_if_true(Instruction* currentInstruction) emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); Jump isZero = branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0)))); - addJump(emitJumpIfImmediateInteger(regT0), target + 2); + addJump(emitJumpIfImmediateInteger(regT0), target); - addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(true)))), target + 2); + addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(true)))), target); addSlowCase(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsBoolean(false))))); isZero.link(this); }; + +void JIT::emit_op_loop_if_false(Instruction* currentInstruction) +{ + emitTimeoutCheck(); + + + unsigned target = currentInstruction[2].u.operand; + emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); + + addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0)))), target); + Jump isNonZero = emitJumpIfImmediateInteger(regT0); + + addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(false)))), target); + addSlowCase(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsBoolean(true))))); + + isNonZero.link(this); + RECORD_JUMP_TARGET(target); +}; + void JIT::emit_op_resolve_base(Instruction* currentInstruction) { JITStubCall stubCall(this, cti_op_resolve_base); @@ -2211,14 +2380,14 @@ void JIT::emit_op_jfalse(Instruction* currentInstruction) unsigned target = currentInstruction[2].u.operand; emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); - addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0)))), target + 2); + addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0)))), target); Jump isNonZero = emitJumpIfImmediateInteger(regT0); - addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(false)))), target + 2); + addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(false)))), target); addSlowCase(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsBoolean(true))))); isNonZero.link(this); - RECORD_JUMP_TARGET(target + 2); + RECORD_JUMP_TARGET(target); }; void JIT::emit_op_jeq_null(Instruction* currentInstruction) { @@ -2230,16 +2399,16 @@ void JIT::emit_op_jeq_null(Instruction* currentInstruction) // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); - addJump(branchTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target + 2); + addJump(branchTest32(NonZero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target); Jump wasNotImmediate = jump(); // Now handle the immediate cases - undefined & null isImmediate.link(this); andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0); - addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNull()))), target + 2); + addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNull()))), target); wasNotImmediate.link(this); - RECORD_JUMP_TARGET(target + 2); + RECORD_JUMP_TARGET(target); }; void JIT::emit_op_jneq_null(Instruction* currentInstruction) { @@ -2251,16 +2420,16 @@ void JIT::emit_op_jneq_null(Instruction* currentInstruction) // First, handle JSCell cases - check MasqueradesAsUndefined bit on the structure. loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); - addJump(branchTest32(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target + 2); + addJump(branchTest32(Zero, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_flags)), Imm32(MasqueradesAsUndefined)), target); Jump wasNotImmediate = jump(); // Now handle the immediate cases - undefined & null isImmediate.link(this); andPtr(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT0); - addJump(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsNull()))), target + 2); + addJump(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsNull()))), target); wasNotImmediate.link(this); - RECORD_JUMP_TARGET(target + 2); + RECORD_JUMP_TARGET(target); } void JIT::emit_op_jneq_ptr(Instruction* currentInstruction) @@ -2270,9 +2439,9 @@ void JIT::emit_op_jneq_ptr(Instruction* currentInstruction) unsigned target = currentInstruction[3].u.operand; emitGetVirtualRegister(src, regT0); - addJump(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue(ptr)))), target + 3); + addJump(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(JSValue(ptr)))), target); - RECORD_JUMP_TARGET(target + 3); + RECORD_JUMP_TARGET(target); } void JIT::emit_op_jsr(Instruction* currentInstruction) @@ -2280,10 +2449,10 @@ void JIT::emit_op_jsr(Instruction* currentInstruction) int retAddrDst = currentInstruction[1].u.operand; int target = currentInstruction[2].u.operand; DataLabelPtr storeLocation = storePtrWithPatch(ImmPtr(0), Address(callFrameRegister, sizeof(Register) * retAddrDst)); - addJump(jump(), target + 2); + addJump(jump(), target); m_jsrSites.append(JSRInfo(storeLocation, label())); killLastResultRegister(); - RECORD_JUMP_TARGET(target + 2); + RECORD_JUMP_TARGET(target); } void JIT::emit_op_sret(Instruction* currentInstruction) @@ -2325,7 +2494,7 @@ void JIT::emit_op_resolve_with_base(Instruction* currentInstruction) void JIT::emit_op_new_func_exp(Instruction* currentInstruction) { JITStubCall stubCall(this, cti_op_new_func_exp); - stubCall.addArgument(ImmPtr(m_codeBlock->functionExpression(currentInstruction[2].u.operand))); + stubCall.addArgument(ImmPtr(m_codeBlock->functionExpr(currentInstruction[2].u.operand))); stubCall.call(currentInstruction[1].u.operand); } @@ -2335,13 +2504,13 @@ void JIT::emit_op_jtrue(Instruction* currentInstruction) emitGetVirtualRegister(currentInstruction[1].u.operand, regT0); Jump isZero = branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsNumber(m_globalData, 0)))); - addJump(emitJumpIfImmediateInteger(regT0), target + 2); + addJump(emitJumpIfImmediateInteger(regT0), target); - addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(true)))), target + 2); + addJump(branchPtr(Equal, regT0, ImmPtr(JSValue::encode(jsBoolean(true)))), target); addSlowCase(branchPtr(NotEqual, regT0, ImmPtr(JSValue::encode(jsBoolean(false))))); isZero.link(this); - RECORD_JUMP_TARGET(target + 2); + RECORD_JUMP_TARGET(target); } void JIT::emit_op_neq(Instruction* currentInstruction) @@ -2392,15 +2561,116 @@ void JIT::emit_op_throw(Instruction* currentInstruction) #endif } +void JIT::emit_op_get_pnames(Instruction* currentInstruction) +{ + int dst = currentInstruction[1].u.operand; + int base = currentInstruction[2].u.operand; + int i = currentInstruction[3].u.operand; + int size = currentInstruction[4].u.operand; + int breakTarget = currentInstruction[5].u.operand; + + JumpList isNotObject; + + emitGetVirtualRegister(base, regT0); + if (!m_codeBlock->isKnownNotImmediate(base)) + isNotObject.append(emitJumpIfNotJSCell(regT0)); + if (base != m_codeBlock->thisRegister()) { + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + isNotObject.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo.m_type)), Imm32(ObjectType))); + } + + // We could inline the case where you have a valid cache, but + // this call doesn't seem to be hot. + Label isObject(this); + JITStubCall getPnamesStubCall(this, cti_op_get_pnames); + getPnamesStubCall.addArgument(regT0); + getPnamesStubCall.call(dst); + load32(Address(regT0, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStringsSize)), regT3); + store32(Imm32(0), addressFor(i)); + store32(regT3, addressFor(size)); + Jump end = jump(); + + isNotObject.link(this); + move(regT0, regT1); + and32(Imm32(~JSImmediate::ExtendedTagBitUndefined), regT1); + addJump(branch32(Equal, regT1, Imm32(JSImmediate::FullTagTypeNull)), breakTarget); + + JITStubCall toObjectStubCall(this, cti_to_object); + toObjectStubCall.addArgument(regT0); + toObjectStubCall.call(base); + jump().linkTo(isObject, this); + + end.link(this); +} + void JIT::emit_op_next_pname(Instruction* currentInstruction) { - JITStubCall stubCall(this, cti_op_next_pname); - stubCall.addArgument(currentInstruction[2].u.operand, regT2); + int dst = currentInstruction[1].u.operand; + int base = currentInstruction[2].u.operand; + int i = currentInstruction[3].u.operand; + int size = currentInstruction[4].u.operand; + int it = currentInstruction[5].u.operand; + int target = currentInstruction[6].u.operand; + + JumpList callHasProperty; + + Label begin(this); + load32(addressFor(i), regT0); + Jump end = branch32(Equal, regT0, addressFor(size)); + + // Grab key @ i + loadPtr(addressFor(it), regT1); + loadPtr(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_jsStrings)), regT2); + +#if USE(JSVALUE64) + loadPtr(BaseIndex(regT2, regT0, TimesEight), regT2); +#else + loadPtr(BaseIndex(regT2, regT0, TimesFour), regT2); +#endif + + emitPutVirtualRegister(dst, regT2); + + // Increment i + add32(Imm32(1), regT0); + store32(regT0, addressFor(i)); + + // Verify that i is valid: + emitGetVirtualRegister(base, regT0); + + // Test base's structure + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + callHasProperty.append(branchPtr(NotEqual, regT2, Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure))))); + + // Test base's prototype chain + loadPtr(Address(Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedPrototypeChain))), regT3); + loadPtr(Address(regT3, OBJECT_OFFSETOF(StructureChain, m_vector)), regT3); + addJump(branchTestPtr(Zero, Address(regT3)), target); + + Label checkPrototype(this); + loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2); + callHasProperty.append(emitJumpIfNotJSCell(regT2)); + loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + callHasProperty.append(branchPtr(NotEqual, regT2, Address(regT3))); + addPtr(Imm32(sizeof(Structure*)), regT3); + branchTestPtr(NonZero, Address(regT3)).linkTo(checkPrototype, this); + + // Continue loop. + addJump(jump(), target); + + // Slow case: Ask the object if i is valid. + callHasProperty.link(this); + emitGetVirtualRegister(dst, regT1); + JITStubCall stubCall(this, cti_has_property); + stubCall.addArgument(regT0); + stubCall.addArgument(regT1); stubCall.call(); - Jump endOfIter = branchTestPtr(Zero, regT0); - emitPutVirtualRegister(currentInstruction[1].u.operand); - addJump(jump(), currentInstruction[3].u.operand + 3); - endOfIter.link(this); + + // Test for valid key. + addJump(branchTest32(NonZero, regT0), target); + jump().linkTo(begin, this); + + // End of loop. + end.link(this); } void JIT::emit_op_push_scope(Instruction* currentInstruction) @@ -2484,8 +2754,8 @@ void JIT::emit_op_jmp_scopes(Instruction* currentInstruction) JITStubCall stubCall(this, cti_op_jmp_scopes); stubCall.addArgument(Imm32(currentInstruction[1].u.operand)); stubCall.call(); - addJump(jump(), currentInstruction[2].u.operand + 2); - RECORD_JUMP_TARGET(currentInstruction[2].u.operand + 2); + addJump(jump(), currentInstruction[2].u.operand); + RECORD_JUMP_TARGET(currentInstruction[2].u.operand); } void JIT::emit_op_switch_imm(Instruction* currentInstruction) @@ -2711,32 +2981,20 @@ void JIT::emitSlow_op_to_primitive(Instruction* currentInstruction, Vector<SlowC void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { - // The slow void JIT::emitSlow_that handles accesses to arrays (below) may jump back up to here. - Label beginGetByValSlow(this); + unsigned dst = currentInstruction[1].u.operand; + unsigned base = currentInstruction[2].u.operand; + unsigned property = currentInstruction[3].u.operand; - Jump notImm = getSlowCase(iter); - linkSlowCase(iter); - linkSlowCase(iter); - emitFastArithIntToImmNoCheck(regT1, regT1); + linkSlowCase(iter); // property int32 check + linkSlowCaseIfNotJSCell(iter, base); // base cell check + linkSlowCase(iter); // base array check + linkSlowCase(iter); // vector length check + linkSlowCase(iter); // empty value - notImm.link(this); JITStubCall stubCall(this, cti_op_get_by_val); - stubCall.addArgument(regT0); - stubCall.addArgument(regT1); - stubCall.call(currentInstruction[1].u.operand); - emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val)); - - // This is slow void JIT::emitSlow_that handles accesses to arrays above the fast cut-off. - // First, check if this is an access to the vector - linkSlowCase(iter); - branch32(AboveOrEqual, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_vectorLength)), beginGetByValSlow); - - // okay, missed the fast region, but it is still in the vector. Get the value. - loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT2); - // Check whether the value loaded is zero; if so we need to return undefined. - branchTestPtr(Zero, regT2, beginGetByValSlow); - move(regT2, regT0); - emitPutVirtualRegister(currentInstruction[1].u.operand, regT0); + stubCall.addArgument(base, regT2); + stubCall.addArgument(property, regT2); + stubCall.call(dst); } void JIT::emitSlow_op_loop_if_less(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -2746,26 +3004,26 @@ void JIT::emitSlow_op_loop_if_less(Instruction* currentInstruction, Vector<SlowC unsigned target = currentInstruction[3].u.operand; if (isOperandConstantImmediateInt(op2)) { linkSlowCase(iter); - JITStubCall stubCall(this, cti_op_loop_if_less); + JITStubCall stubCall(this, cti_op_jless); stubCall.addArgument(regT0); stubCall.addArgument(op2, regT2); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } else if (isOperandConstantImmediateInt(op1)) { linkSlowCase(iter); - JITStubCall stubCall(this, cti_op_loop_if_less); + JITStubCall stubCall(this, cti_op_jless); stubCall.addArgument(op1, regT2); stubCall.addArgument(regT0); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } else { linkSlowCase(iter); linkSlowCase(iter); - JITStubCall stubCall(this, cti_op_loop_if_less); + JITStubCall stubCall(this, cti_op_jless); stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } } @@ -2779,7 +3037,7 @@ void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<Slo stubCall.addArgument(regT0); stubCall.addArgument(currentInstruction[2].u.operand, regT2); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } else { linkSlowCase(iter); linkSlowCase(iter); @@ -2787,36 +3045,26 @@ void JIT::emitSlow_op_loop_if_lesseq(Instruction* currentInstruction, Vector<Slo stubCall.addArgument(regT0); stubCall.addArgument(regT1); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), target + 3); + emitJumpSlowToHot(branchTest32(NonZero, regT0), target); } } void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { - // Normal slow cases - either is not an immediate imm, or is an array. - Jump notImm = getSlowCase(iter); - linkSlowCase(iter); - linkSlowCase(iter); - emitFastArithIntToImmNoCheck(regT1, regT1); + unsigned base = currentInstruction[1].u.operand; + unsigned property = currentInstruction[2].u.operand; + unsigned value = currentInstruction[3].u.operand; - notImm.link(this); { - JITStubCall stubCall(this, cti_op_put_by_val); - stubCall.addArgument(regT0); - stubCall.addArgument(regT1); - stubCall.addArgument(currentInstruction[3].u.operand, regT2); - stubCall.call(); - emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_put_by_val)); - } + linkSlowCase(iter); // property int32 check + linkSlowCaseIfNotJSCell(iter, base); // base cell check + linkSlowCase(iter); // base not array check + linkSlowCase(iter); // in vector check - // slow cases for immediate int accesses to arrays - linkSlowCase(iter); - linkSlowCase(iter); { - JITStubCall stubCall(this, cti_op_put_by_val_array); - stubCall.addArgument(regT0); - stubCall.addArgument(regT1); - stubCall.addArgument(currentInstruction[3].u.operand, regT2); - stubCall.call(); - } + JITStubCall stubPutByValCall(this, cti_op_put_by_val); + stubPutByValCall.addArgument(regT0); + stubPutByValCall.addArgument(property, regT2); + stubPutByValCall.addArgument(value, regT2); + stubPutByValCall.call(); } void JIT::emitSlow_op_loop_if_true(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -2825,7 +3073,16 @@ void JIT::emitSlow_op_loop_if_true(Instruction* currentInstruction, Vector<SlowC JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(regT0); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), currentInstruction[2].u.operand + 2); + emitJumpSlowToHot(branchTest32(NonZero, regT0), currentInstruction[2].u.operand); +} + +void JIT::emitSlow_op_loop_if_false(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + linkSlowCase(iter); + JITStubCall stubCall(this, cti_op_jtrue); + stubCall.addArgument(regT0); + stubCall.call(); + emitJumpSlowToHot(branchTest32(Zero, regT0), currentInstruction[2].u.operand); // inverted! } void JIT::emitSlow_op_not(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -2843,7 +3100,7 @@ void JIT::emitSlow_op_jfalse(Instruction* currentInstruction, Vector<SlowCaseEnt JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(regT0); stubCall.call(); - emitJumpSlowToHot(branchTest32(Zero, regT0), currentInstruction[2].u.operand + 2); // inverted! + emitJumpSlowToHot(branchTest32(Zero, regT0), currentInstruction[2].u.operand); // inverted! } void JIT::emitSlow_op_bitnot(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -2860,7 +3117,7 @@ void JIT::emitSlow_op_jtrue(Instruction* currentInstruction, Vector<SlowCaseEntr JITStubCall stubCall(this, cti_op_jtrue); stubCall.addArgument(regT0); stubCall.call(); - emitJumpSlowToHot(branchTest32(NonZero, regT0), currentInstruction[2].u.operand + 2); + emitJumpSlowToHot(branchTest32(NonZero, regT0), currentInstruction[2].u.operand); } void JIT::emitSlow_op_bitxor(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -2926,16 +3183,20 @@ void JIT::emitSlow_op_nstricteq(Instruction* currentInstruction, Vector<SlowCase void JIT::emitSlow_op_instanceof(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) { - linkSlowCase(iter); - linkSlowCase(iter); - linkSlowCase(iter); - linkSlowCase(iter); + unsigned dst = currentInstruction[1].u.operand; + unsigned value = currentInstruction[2].u.operand; + unsigned baseVal = currentInstruction[3].u.operand; + unsigned proto = currentInstruction[4].u.operand; + + linkSlowCaseIfNotJSCell(iter, value); + linkSlowCaseIfNotJSCell(iter, baseVal); + linkSlowCaseIfNotJSCell(iter, proto); linkSlowCase(iter); JITStubCall stubCall(this, cti_op_instanceof); - stubCall.addArgument(currentInstruction[2].u.operand, regT2); - stubCall.addArgument(currentInstruction[3].u.operand, regT2); - stubCall.addArgument(currentInstruction[4].u.operand, regT2); - stubCall.call(currentInstruction[1].u.operand); + stubCall.addArgument(value, regT2); + stubCall.addArgument(baseVal, regT2); + stubCall.addArgument(proto, regT2); + stubCall.call(dst); } void JIT::emitSlow_op_call(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) diff --git a/JavaScriptCore/jit/JITPropertyAccess.cpp b/JavaScriptCore/jit/JITPropertyAccess.cpp index 9dba2e2..e2995a1 100644 --- a/JavaScriptCore/jit/JITPropertyAccess.cpp +++ b/JavaScriptCore/jit/JITPropertyAccess.cpp @@ -33,6 +33,7 @@ #include "JITStubCall.h" #include "JSArray.h" #include "JSFunction.h" +#include "JSPropertyNameIterator.h" #include "Interpreter.h" #include "LinkBuffer.h" #include "RepatchBuffer.h" @@ -211,12 +212,17 @@ void JIT::emit_op_method_check(Instruction* currentInstruction) emitLoad(base, regT1, regT0); emitJumpSlowCaseIfNotJSCell(base, regT1); + BEGIN_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck); + Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), info.structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))); DataLabelPtr protoStructureToCompare, protoObj = moveWithPatch(ImmPtr(0), regT2); Jump protoStructureCheck = branchPtrWithPatch(NotEqual, Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), protoStructureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))); // This will be relinked to load the function without doing a load. DataLabelPtr putFunction = moveWithPatch(ImmPtr(0), regT0); + + END_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck); + move(Imm32(JSValue::CellTag), regT1); Jump match = jump(); @@ -273,11 +279,14 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); emitJumpSlowCaseIfNotJSCell(base, regT1); addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr))); - addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_fastAccessCutoff)))); - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT0); - load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), regT1); // tag - load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); // payload + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3); + addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); + + load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), regT1); // tag + load32(BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); // payload + addSlowCase(branch32(Equal, regT1, Imm32(JSValue::EmptyValueTag))); + emitStore(dst, regT1, regT0); map(m_bytecodeIndex + OPCODE_LENGTH(op_get_by_val), dst, regT1, regT0); } @@ -288,35 +297,16 @@ void JIT::emitSlow_op_get_by_val(Instruction* currentInstruction, Vector<SlowCas unsigned base = currentInstruction[2].u.operand; unsigned property = currentInstruction[3].u.operand; - // The slow void JIT::emitSlow_that handles accesses to arrays (below) may jump back up to here. - Label callGetByValJITStub(this); - linkSlowCase(iter); // property int32 check linkSlowCaseIfNotJSCell(iter, base); // base cell check linkSlowCase(iter); // base array check + linkSlowCase(iter); // vector length check + linkSlowCase(iter); // empty value JITStubCall stubCall(this, cti_op_get_by_val); stubCall.addArgument(base); stubCall.addArgument(property); stubCall.call(dst); - - emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val)); - - linkSlowCase(iter); // array fast cut-off check - - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT0); - branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(ArrayStorage, m_vectorLength)), callGetByValJITStub); - - // Missed the fast region, but it is still in the vector. - load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), regT1); // tag - load32(BaseIndex(regT0, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); // payload - - // FIXME: Maybe we can optimize this comparison to JSValue(). - Jump skip = branch32(NotEqual, regT0, Imm32(0)); - branch32(Equal, regT1, Imm32(JSValue::CellTag), callGetByValJITStub); - - skip.link(this); - emitStore(dst, regT1, regT0); } void JIT::emit_op_put_by_val(Instruction* currentInstruction) @@ -330,24 +320,27 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) addSlowCase(branch32(NotEqual, regT3, Imm32(JSValue::Int32Tag))); emitJumpSlowCaseIfNotJSCell(base, regT1); addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr))); - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3); + addSlowCase(branch32(AboveOrEqual, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); - Jump inFastVector = branch32(Below, regT2, Address(regT0, OBJECT_OFFSETOF(JSArray, m_fastAccessCutoff))); - - // Check if the access is within the vector. - addSlowCase(branch32(AboveOrEqual, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_vectorLength)))); - - // This is a write to the slow part of the vector; first, we have to check if this would be the first write to this location. - // FIXME: should be able to handle initial write to array; increment the the number of items in the array, and potentially update fast access cutoff. - Jump skip = branch32(NotEqual, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), Imm32(JSValue::CellTag)); - addSlowCase(branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), Imm32(0))); - skip.link(this); + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT3); - inFastVector.link(this); + Jump empty = branch32(Equal, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4), Imm32(JSValue::EmptyValueTag)); + Label storeResult(this); emitLoad(value, regT1, regT0); store32(regT0, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); // payload store32(regT1, BaseIndex(regT3, regT2, TimesEight, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]) + 4)); // tag + Jump end = jump(); + + empty.link(this); + add32(Imm32(1), Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); + branch32(Below, regT2, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this); + + add32(Imm32(1), regT2, regT0); + store32(regT0, Address(regT3, OBJECT_OFFSETOF(ArrayStorage, m_length))); + jump().linkTo(storeResult, this); + + end.link(this); } void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -359,24 +352,13 @@ void JIT::emitSlow_op_put_by_val(Instruction* currentInstruction, Vector<SlowCas linkSlowCase(iter); // property int32 check linkSlowCaseIfNotJSCell(iter, base); // base cell check linkSlowCase(iter); // base not array check + linkSlowCase(iter); // in vector check JITStubCall stubPutByValCall(this, cti_op_put_by_val); stubPutByValCall.addArgument(base); stubPutByValCall.addArgument(property); stubPutByValCall.addArgument(value); stubPutByValCall.call(); - - emitJumpSlowToHot(jump(), OPCODE_LENGTH(op_get_by_val)); - - // Slow cases for immediate int accesses to arrays. - linkSlowCase(iter); // in vector check - linkSlowCase(iter); // written to slot check - - JITStubCall stubCall(this, cti_op_put_by_val_array); - stubCall.addArgument(regT1, regT0); - stubCall.addArgument(regT2); - stubCall.addArgument(value); - stubCall.call(); } void JIT::emit_op_get_by_id(Instruction* currentInstruction) @@ -397,6 +379,9 @@ void JIT::compileGetByIdHotPath() // Additionally, for get_by_id we need patch the offset of the branch to the slow case (we patch this to jump // to array-length / prototype access tranpolines, and finally we also the the property-map access offset as a label // to jump back to if one of these trampolies finds a match. + + BEGIN_UNINTERRUPTED_SEQUENCE(sequenceGetByIdHotPath); + Label hotPathBegin(this); m_propertyAccessCompilationInfo[m_propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; m_propertyAccessInstructionIndex++; @@ -419,6 +404,8 @@ void JIT::compileGetByIdHotPath() Label putResult(this); ASSERT(differenceBetween(hotPathBegin, putResult) == patchOffsetGetByIdPutResult); + + END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdHotPath); } void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -440,13 +427,18 @@ void JIT::compileGetByIdSlowCase(int dst, int base, Identifier* ident, Vector<Sl linkSlowCaseIfNotJSCell(iter, base); linkSlowCase(iter); - Label coldPathBegin(this); + BEGIN_UNINTERRUPTED_SEQUENCE(sequenceGetByIdSlowCase); +#ifndef NDEBUG + Label coldPathBegin(this); +#endif JITStubCall stubCall(this, isMethodCheck ? cti_op_get_by_id_method_check : cti_op_get_by_id); stubCall.addArgument(regT1, regT0); stubCall.addArgument(ImmPtr(ident)); Call call = stubCall.call(dst); + END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdSlowCase); + ASSERT(differenceBetween(coldPathBegin, call) == patchOffsetGetByIdSlowCaseCall); // Track the location of the call; this will be used to recover patch information. @@ -467,6 +459,8 @@ void JIT::emit_op_put_by_id(Instruction* currentInstruction) emitJumpSlowCaseIfNotJSCell(base, regT1); + BEGIN_UNINTERRUPTED_SEQUENCE(sequencePutById); + Label hotPathBegin(this); m_propertyAccessCompilationInfo[m_propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; m_propertyAccessInstructionIndex++; @@ -484,6 +478,9 @@ void JIT::emit_op_put_by_id(Instruction* currentInstruction) DataLabel32 displacementLabel1 = storePtrWithAddressOffsetPatch(regT2, Address(regT0, patchGetByIdDefaultOffset)); // payload DataLabel32 displacementLabel2 = storePtrWithAddressOffsetPatch(regT3, Address(regT0, patchGetByIdDefaultOffset)); // tag + + END_UNINTERRUPTED_SEQUENCE(sequencePutById); + ASSERT(differenceBetween(hotPathBegin, displacementLabel1) == patchOffsetPutByIdPropertyMapOffset1); ASSERT(differenceBetween(hotPathBegin, displacementLabel2) == patchOffsetPutByIdPropertyMapOffset2); } @@ -545,22 +542,26 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID res load32(Address(temp, offset + 4), resultTag); } +void JIT::testPrototype(Structure* structure, JumpList& failureCases) +{ + if (structure->m_prototype.isNull()) + return; + + failureCases.append(branchPtr(NotEqual, AbsoluteAddress(&asCell(structure->m_prototype)->m_structure), ImmPtr(asCell(structure->m_prototype)->m_structure))); +} + void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress) { // It is assumed that regT0 contains the basePayload and regT1 contains the baseTag. The value can be found on the stack. JumpList failureCases; failureCases.append(branch32(NotEqual, regT1, Imm32(JSValue::CellTag))); - - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); - failureCases.append(branchPtr(NotEqual, regT2, ImmPtr(oldStructure))); + failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure))); + testPrototype(oldStructure, failureCases); // Verify that nothing in the prototype chain has a setter for this property. - for (RefPtr<Structure>* it = chain->head(); *it; ++it) { - loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2); - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); - failureCases.append(branchPtr(NotEqual, regT2, ImmPtr(it->get()))); - } + for (RefPtr<Structure>* it = chain->head(); *it; ++it) + testPrototype(it->get(), failureCases); // Reallocate property storage if needed. Call callTarget; @@ -954,16 +955,83 @@ void JIT::privateCompileGetByIdChain(StructureStubInfo* stubInfo, Structure* str #endif // !ENABLE(JIT_OPTIMIZE_PROPERTY_ACCESS) +void JIT::compileGetDirectOffset(RegisterID base, RegisterID resultTag, RegisterID resultPayload, RegisterID structure, RegisterID offset) +{ + ASSERT(sizeof(((Structure*)0)->m_propertyStorageCapacity) == sizeof(int32_t)); + ASSERT(sizeof(JSObject::inlineStorageCapacity) == sizeof(int32_t)); + ASSERT(sizeof(JSValue) == 8); + + Jump notUsingInlineStorage = branch32(NotEqual, Address(structure, OBJECT_OFFSETOF(Structure, m_propertyStorageCapacity)), Imm32(JSObject::inlineStorageCapacity)); + loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage)+OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload); + loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSObject, m_inlineStorage)+OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag); + Jump finishedLoad = jump(); + notUsingInlineStorage.link(this); + loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), base); + loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.payload)), resultPayload); + loadPtr(BaseIndex(base, offset, TimesEight, OBJECT_OFFSETOF(JSValue, u.asBits.tag)), resultTag); + finishedLoad.link(this); +} + +void JIT::emit_op_get_by_pname(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned base = currentInstruction[2].u.operand; + unsigned property = currentInstruction[3].u.operand; + unsigned expected = currentInstruction[4].u.operand; + unsigned iter = currentInstruction[5].u.operand; + unsigned i = currentInstruction[6].u.operand; + + emitLoad2(property, regT1, regT0, base, regT3, regT2); + emitJumpSlowCaseIfNotJSCell(property, regT1); + addSlowCase(branchPtr(NotEqual, regT0, payloadFor(expected))); + // Property registers are now available as the property is known + emitJumpSlowCaseIfNotJSCell(base, regT3); + emitLoadPayload(iter, regT1); + + // Test base's structure + loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT0); + addSlowCase(branchPtr(NotEqual, regT0, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))); + load32(addressFor(i), regT3); + sub32(Imm32(1), regT3); + addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots)))); + compileGetDirectOffset(regT2, regT1, regT0, regT0, regT3); + + emitStore(dst, regT1, regT0); + map(m_bytecodeIndex + OPCODE_LENGTH(op_get_by_pname), dst, regT1, regT0); +} + +void JIT::emitSlow_op_get_by_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned base = currentInstruction[2].u.operand; + unsigned property = currentInstruction[3].u.operand; + + linkSlowCaseIfNotJSCell(iter, property); + linkSlowCase(iter); + linkSlowCaseIfNotJSCell(iter, base); + linkSlowCase(iter); + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_get_by_val); + stubCall.addArgument(base); + stubCall.addArgument(property); + stubCall.call(dst); +} + #else // USE(JSVALUE32_64) void JIT::emit_op_get_by_val(Instruction* currentInstruction) { - emitGetVirtualRegisters(currentInstruction[2].u.operand, regT0, currentInstruction[3].u.operand, regT1); + unsigned dst = currentInstruction[1].u.operand; + unsigned base = currentInstruction[2].u.operand; + unsigned property = currentInstruction[3].u.operand; + + emitGetVirtualRegisters(base, regT0, property, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT1); #if USE(JSVALUE64) // This is technically incorrect - we're zero-extending an int32. On the hot path this doesn't matter. - // We check the value as if it was a uint32 against the m_fastAccessCutoff - which will always fail if - // number was signed since m_fastAccessCutoff is always less than intmax (since the total allocation + // We check the value as if it was a uint32 against the m_vectorLength - which will always fail if + // number was signed since m_vectorLength is always less than intmax (since the total allocation // size is always less than 4Gb). As such zero extending wil have been correct (and extending the value // to 64-bits is necessary since it's used in the address calculation. We zero extend rather than sign // extending since it makes it easier to re-tag the value in the slow case. @@ -971,21 +1039,67 @@ void JIT::emit_op_get_by_val(Instruction* currentInstruction) #else emitFastArithImmToInt(regT1); #endif - emitJumpSlowCaseIfNotJSCell(regT0); + emitJumpSlowCaseIfNotJSCell(regT0, base); addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr))); - // This is an array; get the m_storage pointer into ecx, then check if the index is below the fast cutoff loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2); - addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_fastAccessCutoff)))); + addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); - // Get the value from the vector loadPtr(BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])), regT0); - emitPutVirtualRegister(currentInstruction[1].u.operand); + addSlowCase(branchTestPtr(Zero, regT0)); + + emitPutVirtualRegister(dst); +} + +void JIT::emit_op_get_by_pname(Instruction* currentInstruction) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned base = currentInstruction[2].u.operand; + unsigned property = currentInstruction[3].u.operand; + unsigned expected = currentInstruction[4].u.operand; + unsigned iter = currentInstruction[5].u.operand; + unsigned i = currentInstruction[6].u.operand; + + emitGetVirtualRegister(property, regT0); + addSlowCase(branchPtr(NotEqual, regT0, addressFor(expected))); + emitGetVirtualRegisters(base, regT0, iter, regT1); + emitJumpSlowCaseIfNotJSCell(regT0, base); + + // Test base's structure + loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); + addSlowCase(branchPtr(NotEqual, regT2, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_cachedStructure)))); + load32(addressFor(i), regT3); + sub32(Imm32(1), regT3); + addSlowCase(branch32(AboveOrEqual, regT3, Address(regT1, OBJECT_OFFSETOF(JSPropertyNameIterator, m_numCacheableSlots)))); + compileGetDirectOffset(regT0, regT0, regT2, regT3, regT1); + + emitPutVirtualRegister(dst, regT0); +} + +void JIT::emitSlow_op_get_by_pname(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) +{ + unsigned dst = currentInstruction[1].u.operand; + unsigned base = currentInstruction[2].u.operand; + unsigned property = currentInstruction[3].u.operand; + + linkSlowCase(iter); + linkSlowCaseIfNotJSCell(iter, base); + linkSlowCase(iter); + linkSlowCase(iter); + + JITStubCall stubCall(this, cti_op_get_by_val); + stubCall.addArgument(base, regT2); + stubCall.addArgument(property, regT2); + stubCall.call(dst); } void JIT::emit_op_put_by_val(Instruction* currentInstruction) { - emitGetVirtualRegisters(currentInstruction[1].u.operand, regT0, currentInstruction[2].u.operand, regT1); + unsigned base = currentInstruction[1].u.operand; + unsigned property = currentInstruction[2].u.operand; + unsigned value = currentInstruction[3].u.operand; + + emitGetVirtualRegisters(base, regT0, property, regT1); emitJumpSlowCaseIfNotImmediateInteger(regT1); #if USE(JSVALUE64) // See comment in op_get_by_val. @@ -993,23 +1107,29 @@ void JIT::emit_op_put_by_val(Instruction* currentInstruction) #else emitFastArithImmToInt(regT1); #endif - emitJumpSlowCaseIfNotJSCell(regT0); + emitJumpSlowCaseIfNotJSCell(regT0, base); addSlowCase(branchPtr(NotEqual, Address(regT0), ImmPtr(m_globalData->jsArrayVPtr))); + addSlowCase(branch32(AboveOrEqual, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_vectorLength)))); - // This is an array; get the m_storage pointer into ecx, then check if the index is below the fast cutoff loadPtr(Address(regT0, OBJECT_OFFSETOF(JSArray, m_storage)), regT2); - Jump inFastVector = branch32(Below, regT1, Address(regT0, OBJECT_OFFSETOF(JSArray, m_fastAccessCutoff))); - // No; oh well, check if the access if within the vector - if so, we may still be okay. - addSlowCase(branch32(AboveOrEqual, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_vectorLength)))); - // This is a write to the slow part of the vector; first, we have to check if this would be the first write to this location. - // FIXME: should be able to handle initial write to array; increment the the number of items in the array, and potentially update fast access cutoff. - addSlowCase(branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0])))); + Jump empty = branchTestPtr(Zero, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); - // All good - put the value into the array. - inFastVector.link(this); - emitGetVirtualRegister(currentInstruction[3].u.operand, regT0); + Label storeResult(this); + emitGetVirtualRegister(value, regT0); storePtr(regT0, BaseIndex(regT2, regT1, ScalePtr, OBJECT_OFFSETOF(ArrayStorage, m_vector[0]))); + Jump end = jump(); + + empty.link(this); + add32(Imm32(1), Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_numValuesInVector))); + branch32(Below, regT1, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length))).linkTo(storeResult, this); + + move(regT1, regT0); + add32(Imm32(1), regT0); + store32(regT0, Address(regT2, OBJECT_OFFSETOF(ArrayStorage, m_length))); + jump().linkTo(storeResult, this); + + end.link(this); } void JIT::emit_op_put_by_index(Instruction* currentInstruction) @@ -1122,18 +1242,25 @@ void JIT::emit_op_method_check(Instruction* currentInstruction) // Do the method check - check the object & its prototype's structure inline (this is the common case). m_methodCallCompilationInfo.append(MethodCallCompilationInfo(m_propertyAccessInstructionIndex)); MethodCallCompilationInfo& info = m_methodCallCompilationInfo.last(); + Jump notCell = emitJumpIfNotJSCell(regT0); + + BEGIN_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck); + Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), info.structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))); DataLabelPtr protoStructureToCompare, protoObj = moveWithPatch(ImmPtr(0), regT1); Jump protoStructureCheck = branchPtrWithPatch(NotEqual, Address(regT1, OBJECT_OFFSETOF(JSCell, m_structure)), protoStructureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))); // This will be relinked to load the function without doing a load. DataLabelPtr putFunction = moveWithPatch(ImmPtr(0), regT0); + + END_UNINTERRUPTED_SEQUENCE(sequenceMethodCheck); + Jump match = jump(); - ASSERT(differenceBetween(info.structureToCompare, protoObj) == patchOffsetMethodCheckProtoObj); - ASSERT(differenceBetween(info.structureToCompare, protoStructureToCompare) == patchOffsetMethodCheckProtoStruct); - ASSERT(differenceBetween(info.structureToCompare, putFunction) == patchOffsetMethodCheckPutFunction); + ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, protoObj), patchOffsetMethodCheckProtoObj); + ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, protoStructureToCompare), patchOffsetMethodCheckProtoStruct); + ASSERT_JIT_OFFSET(differenceBetween(info.structureToCompare, putFunction), patchOffsetMethodCheckPutFunction); // Link the failure cases here. notCell.link(this); @@ -1192,25 +1319,30 @@ void JIT::compileGetByIdHotPath(int, int baseVReg, Identifier*, unsigned propert emitJumpSlowCaseIfNotJSCell(regT0, baseVReg); + BEGIN_UNINTERRUPTED_SEQUENCE(sequenceGetByIdHotPath); + Label hotPathBegin(this); m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; DataLabelPtr structureToCompare; Jump structureCheck = branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure))); addSlowCase(structureCheck); - ASSERT(differenceBetween(hotPathBegin, structureToCompare) == patchOffsetGetByIdStructure); - ASSERT(differenceBetween(hotPathBegin, structureCheck) == patchOffsetGetByIdBranchToSlowCase); + ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetGetByIdStructure); + ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureCheck), patchOffsetGetByIdBranchToSlowCase) Label externalLoad = loadPtrWithPatchToLEA(Address(regT0, OBJECT_OFFSETOF(JSObject, m_externalStorage)), regT0); Label externalLoadComplete(this); - ASSERT(differenceBetween(hotPathBegin, externalLoad) == patchOffsetGetByIdExternalLoad); - ASSERT(differenceBetween(externalLoad, externalLoadComplete) == patchLengthGetByIdExternalLoad); + ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, externalLoad), patchOffsetGetByIdExternalLoad); + ASSERT_JIT_OFFSET(differenceBetween(externalLoad, externalLoadComplete), patchLengthGetByIdExternalLoad); DataLabel32 displacementLabel = loadPtrWithAddressOffsetPatch(Address(regT0, patchGetByIdDefaultOffset), regT0); - ASSERT(differenceBetween(hotPathBegin, displacementLabel) == patchOffsetGetByIdPropertyMapOffset); + ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel), patchOffsetGetByIdPropertyMapOffset); Label putResult(this); - ASSERT(differenceBetween(hotPathBegin, putResult) == patchOffsetGetByIdPutResult); + + END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdHotPath); + + ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, putResult), patchOffsetGetByIdPutResult); } void JIT::emitSlow_op_get_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -1233,6 +1365,8 @@ void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident linkSlowCaseIfNotJSCell(iter, baseVReg); linkSlowCase(iter); + BEGIN_UNINTERRUPTED_SEQUENCE(sequenceGetByIdSlowCase); + #ifndef NDEBUG Label coldPathBegin(this); #endif @@ -1241,7 +1375,9 @@ void JIT::compileGetByIdSlowCase(int resultVReg, int baseVReg, Identifier* ident stubCall.addArgument(ImmPtr(ident)); Call call = stubCall.call(resultVReg); - ASSERT(differenceBetween(coldPathBegin, call) == patchOffsetGetByIdSlowCaseCall); + END_UNINTERRUPTED_SEQUENCE(sequenceGetByIdSlowCase); + + ASSERT_JIT_OFFSET(differenceBetween(coldPathBegin, call), patchOffsetGetByIdSlowCaseCall); // Track the location of the call; this will be used to recover patch information. m_propertyAccessCompilationInfo[m_propertyAccessInstructionIndex].callReturnLocation = call; @@ -1264,22 +1400,27 @@ void JIT::emit_op_put_by_id(Instruction* currentInstruction) // Jump to a slow case if either the base object is an immediate, or if the Structure does not match. emitJumpSlowCaseIfNotJSCell(regT0, baseVReg); + BEGIN_UNINTERRUPTED_SEQUENCE(sequencePutById); + Label hotPathBegin(this); m_propertyAccessCompilationInfo[propertyAccessInstructionIndex].hotPathBegin = hotPathBegin; // It is important that the following instruction plants a 32bit immediate, in order that it can be patched over. DataLabelPtr structureToCompare; addSlowCase(branchPtrWithPatch(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), structureToCompare, ImmPtr(reinterpret_cast<void*>(patchGetByIdDefaultStructure)))); - ASSERT(differenceBetween(hotPathBegin, structureToCompare) == patchOffsetPutByIdStructure); + ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, structureToCompare), patchOffsetPutByIdStructure); // Plant a load from a bogus ofset in the object's property map; we will patch this later, if it is to be used. Label externalLoad = loadPtrWithPatchToLEA(Address(regT0, OBJECT_OFFSETOF(JSObject, m_externalStorage)), regT0); Label externalLoadComplete(this); - ASSERT(differenceBetween(hotPathBegin, externalLoad) == patchOffsetPutByIdExternalLoad); - ASSERT(differenceBetween(externalLoad, externalLoadComplete) == patchLengthPutByIdExternalLoad); + ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, externalLoad), patchOffsetPutByIdExternalLoad); + ASSERT_JIT_OFFSET(differenceBetween(externalLoad, externalLoadComplete), patchLengthPutByIdExternalLoad); DataLabel32 displacementLabel = storePtrWithAddressOffsetPatch(regT1, Address(regT0, patchGetByIdDefaultOffset)); - ASSERT(differenceBetween(hotPathBegin, displacementLabel) == patchOffsetPutByIdPropertyMapOffset); + + END_UNINTERRUPTED_SEQUENCE(sequencePutById); + + ASSERT_JIT_OFFSET(differenceBetween(hotPathBegin, displacementLabel), patchOffsetPutByIdPropertyMapOffset); } void JIT::emitSlow_op_put_by_id(Instruction* currentInstruction, Vector<SlowCaseEntry>::iterator& iter) @@ -1336,35 +1477,41 @@ void JIT::compileGetDirectOffset(JSObject* base, RegisterID temp, RegisterID res } } +void JIT::compileGetDirectOffset(RegisterID base, RegisterID result, RegisterID structure, RegisterID offset, RegisterID scratch) +{ + ASSERT(sizeof(((Structure*)0)->m_propertyStorageCapacity) == sizeof(int32_t)); + ASSERT(sizeof(JSObject::inlineStorageCapacity) == sizeof(int32_t)); + + Jump notUsingInlineStorage = branch32(NotEqual, Address(structure, OBJECT_OFFSETOF(Structure, m_propertyStorageCapacity)), Imm32(JSObject::inlineStorageCapacity)); + loadPtr(BaseIndex(base, offset, ScalePtr, OBJECT_OFFSETOF(JSObject, m_inlineStorage)), result); + Jump finishedLoad = jump(); + notUsingInlineStorage.link(this); + loadPtr(Address(base, OBJECT_OFFSETOF(JSObject, m_externalStorage)), scratch); + loadPtr(BaseIndex(scratch, offset, ScalePtr, 0), result); + finishedLoad.link(this); +} + +void JIT::testPrototype(Structure* structure, JumpList& failureCases) +{ + if (structure->m_prototype.isNull()) + return; + + move(ImmPtr(&asCell(structure->m_prototype)->m_structure), regT2); + move(ImmPtr(asCell(structure->m_prototype)->m_structure), regT3); + failureCases.append(branchPtr(NotEqual, Address(regT2), regT3)); +} + void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure* oldStructure, Structure* newStructure, size_t cachedOffset, StructureChain* chain, ReturnAddressPtr returnAddress) { JumpList failureCases; // Check eax is an object of the right Structure. failureCases.append(emitJumpIfNotJSCell(regT0)); failureCases.append(branchPtr(NotEqual, Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(oldStructure))); - JumpList successCases; + testPrototype(oldStructure, failureCases); - // ecx = baseObject - loadPtr(Address(regT0, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); - // proto(ecx) = baseObject->structure()->prototype() - failureCases.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType))); - - loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2); - // ecx = baseObject->m_structure - for (RefPtr<Structure>* it = chain->head(); *it; ++it) { - // null check the prototype - successCases.append(branchPtr(Equal, regT2, ImmPtr(JSValue::encode(jsNull())))); - - // Check the structure id - failureCases.append(branchPtr(NotEqual, Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), ImmPtr(it->get()))); - - loadPtr(Address(regT2, OBJECT_OFFSETOF(JSCell, m_structure)), regT2); - failureCases.append(branch32(NotEqual, Address(regT2, OBJECT_OFFSETOF(Structure, m_typeInfo) + OBJECT_OFFSETOF(TypeInfo, m_type)), Imm32(ObjectType))); - loadPtr(Address(regT2, OBJECT_OFFSETOF(Structure, m_prototype)), regT2); - } - - successCases.link(this); + for (RefPtr<Structure>* it = chain->head(); *it; ++it) + testPrototype(it->get(), failureCases); Call callTarget; @@ -1382,7 +1529,7 @@ void JIT::privateCompilePutByIdTransition(StructureStubInfo* stubInfo, Structure stubCall.addArgument(Imm32(oldStructure->propertyStorageCapacity())); stubCall.addArgument(Imm32(newStructure->propertyStorageCapacity())); stubCall.call(regT0); - emitGetJITStubArg(3, regT1); + emitGetJITStubArg(2, regT1); restoreReturnAddressBeforeReturn(regT3); } diff --git a/JavaScriptCore/jit/JITStubCall.h b/JavaScriptCore/jit/JITStubCall.h index cb5354b..cfbd7dc 100644 --- a/JavaScriptCore/jit/JITStubCall.h +++ b/JavaScriptCore/jit/JITStubCall.h @@ -26,7 +26,7 @@ #ifndef JITStubCall_h #define JITStubCall_h -#include <wtf/Platform.h> +#include "MacroAssemblerCodeRef.h" #if ENABLE(JIT) @@ -36,58 +36,58 @@ namespace JSC { public: JITStubCall(JIT* jit, JSObject* (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) : m_jit(jit) - , m_stub(reinterpret_cast<void*>(stub)) + , m_stub(stub) , m_returnType(Cell) - , m_stackIndex(stackIndexStart) + , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) { } JITStubCall(JIT* jit, JSPropertyNameIterator* (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) : m_jit(jit) - , m_stub(reinterpret_cast<void*>(stub)) + , m_stub(stub) , m_returnType(Cell) - , m_stackIndex(stackIndexStart) + , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) { } JITStubCall(JIT* jit, void* (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) : m_jit(jit) - , m_stub(reinterpret_cast<void*>(stub)) + , m_stub(stub) , m_returnType(VoidPtr) - , m_stackIndex(stackIndexStart) + , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) { } JITStubCall(JIT* jit, int (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) : m_jit(jit) - , m_stub(reinterpret_cast<void*>(stub)) + , m_stub(stub) , m_returnType(Int) - , m_stackIndex(stackIndexStart) + , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) { } JITStubCall(JIT* jit, bool (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) : m_jit(jit) - , m_stub(reinterpret_cast<void*>(stub)) + , m_stub(stub) , m_returnType(Int) - , m_stackIndex(stackIndexStart) + , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) { } JITStubCall(JIT* jit, void (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) : m_jit(jit) - , m_stub(reinterpret_cast<void*>(stub)) + , m_stub(stub) , m_returnType(Void) - , m_stackIndex(stackIndexStart) + , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) { } #if USE(JSVALUE32_64) JITStubCall(JIT* jit, EncodedJSValue (JIT_STUB *stub)(STUB_ARGS_DECLARATION)) : m_jit(jit) - , m_stub(reinterpret_cast<void*>(stub)) + , m_stub(stub) , m_returnType(Value) - , m_stackIndex(stackIndexStart) + , m_stackIndex(JITSTACKFRAME_ARGS_INDEX) { } #endif @@ -145,7 +145,7 @@ namespace JSC { void getArgument(size_t argumentNumber, JIT::RegisterID tag, JIT::RegisterID payload) { - size_t stackIndex = stackIndexStart + (argumentNumber * stackIndexStep); + size_t stackIndex = JITSTACKFRAME_ARGS_INDEX + (argumentNumber * stackIndexStep); m_jit->peek(payload, stackIndex); m_jit->peek(tag, stackIndex + 1); } @@ -171,7 +171,7 @@ namespace JSC { m_jit->restoreArgumentReference(); JIT::Call call = m_jit->call(); - m_jit->m_calls.append(CallRecord(call, m_jit->m_bytecodeIndex, m_stub)); + m_jit->m_calls.append(CallRecord(call, m_jit->m_bytecodeIndex, m_stub.value())); #if ENABLE(OPCODE_SAMPLING) if (m_jit->m_bytecodeIndex != (unsigned)-1) @@ -222,10 +222,9 @@ namespace JSC { private: static const size_t stackIndexStep = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 2 : 1; - static const size_t stackIndexStart = 1; // Index 0 is reserved for restoreArgumentReference(). JIT* m_jit; - void* m_stub; + FunctionPtr m_stub; enum { Void, VoidPtr, Int, Value, Cell } m_returnType; size_t m_stackIndex; }; diff --git a/JavaScriptCore/jit/JITStubs.cpp b/JavaScriptCore/jit/JITStubs.cpp index d563f58..cace8b2 100644 --- a/JavaScriptCore/jit/JITStubs.cpp +++ b/JavaScriptCore/jit/JITStubs.cpp @@ -56,6 +56,7 @@ #include "RegExpPrototype.h" #include "Register.h" #include "SamplingTool.h" +#include <wtf/StdLibExtras.h> #include <stdarg.h> #include <stdio.h> @@ -69,6 +70,31 @@ namespace JSC { #define SYMBOL_STRING(name) #name #endif +#if PLATFORM(IPHONE) +#define THUMB_FUNC_PARAM(name) SYMBOL_STRING(name) +#else +#define THUMB_FUNC_PARAM(name) +#endif + +#if PLATFORM(LINUX) && PLATFORM(X86_64) +#define SYMBOL_STRING_RELOCATION(name) #name "@plt" +#else +#define SYMBOL_STRING_RELOCATION(name) SYMBOL_STRING(name) +#endif + +#if PLATFORM(DARWIN) + // Mach-O platform +#define HIDE_SYMBOL(name) ".private_extern _" #name +#elif PLATFORM(AIX) + // IBM's own file format +#define HIDE_SYMBOL(name) ".lglobl " #name +#elif PLATFORM(LINUX) || PLATFORM(FREEBSD) || PLATFORM(OPENBSD) || PLATFORM(SOLARIS) || (PLATFORM(HPUX) && PLATFORM(IA64)) || PLATFORM(SYMBIAN) || PLATFORM(NETBSD) + // ELF platform +#define HIDE_SYMBOL(name) ".hidden " #name +#else +#define HIDE_SYMBOL(name) +#endif + #if USE(JSVALUE32_64) #if COMPILER(GCC) && PLATFORM(X86) @@ -81,7 +107,9 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, callFrame) == 0x58, JITStackFrame_ COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x50, JITStackFrame_code_offset_matches_ctiTrampoline); asm volatile ( +".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushl %ebp" "\n" "movl %esp, %ebp" "\n" @@ -102,11 +130,12 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" asm volatile ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" #if !USE(JIT_STUB_ARGUMENT_VA_LIST) "movl %esp, %ecx" "\n" #endif - "call " SYMBOL_STRING(cti_vm_throw) "\n" + "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" "addl $0x3c, %esp" "\n" "popl %ebx" "\n" "popl %edi" "\n" @@ -117,6 +146,7 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" asm volatile ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addl $0x3c, %esp" "\n" "popl %ebx" "\n" @@ -141,6 +171,7 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x80, JITStackFrame_code_ asm volatile ( ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushq %rbp" "\n" "movq %rsp, %rbp" "\n" @@ -167,9 +198,10 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" asm volatile ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" - "call " SYMBOL_STRING(cti_vm_throw) "\n" + "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" "addq $0x48, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" @@ -182,6 +214,7 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" asm volatile ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addq $0x48, %rsp" "\n" "popq %rbx" "\n" @@ -193,7 +226,7 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ret" "\n" ); -#elif COMPILER(GCC) && PLATFORM_ARM_ARCH(7) +#elif COMPILER(GCC) && PLATFORM(ARM_THUMB2) #if USE(JIT_STUB_ARGUMENT_VA_LIST) #error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7." @@ -203,8 +236,9 @@ asm volatile ( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiTrampoline) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "sub sp, sp, #0x3c" "\n" "str lr, [sp, #0x20]" "\n" @@ -229,11 +263,12 @@ asm volatile ( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "cpy r0, sp" "\n" - "bl " SYMBOL_STRING(cti_vm_throw) "\n" + "bl " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" "ldr r6, [sp, #0x2c]" "\n" "ldr r5, [sp, #0x28]" "\n" "ldr r4, [sp, #0x24]" "\n" @@ -247,7 +282,7 @@ asm volatile ( ".align 2" "\n" ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ldr r6, [sp, #0x2c]" "\n" "ldr r5, [sp, #0x28]" "\n" @@ -257,6 +292,40 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "bx lr" "\n" ); +#elif COMPILER(GCC) && PLATFORM(ARM_TRADITIONAL) + +asm volatile ( +".globl " SYMBOL_STRING(ctiTrampoline) "\n" +SYMBOL_STRING(ctiTrampoline) ":" "\n" + "stmdb sp!, {r1-r3}" "\n" + "stmdb sp!, {r4-r8, lr}" "\n" + "sub sp, sp, #68" "\n" + "mov r4, r2" "\n" + "mov r5, #512" "\n" + // r0 contains the code + "mov lr, pc" "\n" + "mov pc, r0" "\n" + "add sp, sp, #68" "\n" + "ldmia sp!, {r4-r8, lr}" "\n" + "add sp, sp, #12" "\n" + "mov pc, lr" "\n" +); + +asm volatile ( +".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" + "mov r0, sp" "\n" + "bl " SYMBOL_STRING(cti_vm_throw) "\n" + +// Both has the same return sequence +".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" + "add sp, sp, #68" "\n" + "ldmia sp!, {r4-r8, lr}" "\n" + "add sp, sp, #12" "\n" + "mov pc, lr" "\n" +); + #elif COMPILER(MSVC) #if USE(JIT_STUB_ARGUMENT_VA_LIST) @@ -334,7 +403,9 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x30, JITStackFrame_code_ COMPILE_ASSERT(offsetof(struct JITStackFrame, savedEBX) == 0x1c, JITStackFrame_stub_argument_space_matches_ctiTrampoline); asm volatile ( +".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushl %ebp" "\n" "movl %esp, %ebp" "\n" @@ -355,11 +426,12 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" asm volatile ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" #if !USE(JIT_STUB_ARGUMENT_VA_LIST) "movl %esp, %ecx" "\n" #endif - "call " SYMBOL_STRING(cti_vm_throw) "\n" + "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" "addl $0x1c, %esp" "\n" "popl %ebx" "\n" "popl %edi" "\n" @@ -370,6 +442,7 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" asm volatile ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addl $0x1c, %esp" "\n" "popl %ebx" "\n" @@ -392,7 +465,9 @@ COMPILE_ASSERT(offsetof(struct JITStackFrame, code) == 0x48, JITStackFrame_code_ COMPILE_ASSERT(offsetof(struct JITStackFrame, savedRBX) == 0x78, JITStackFrame_stub_argument_space_matches_ctiTrampoline); asm volatile ( +".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "pushq %rbp" "\n" "movq %rsp, %rbp" "\n" @@ -426,9 +501,10 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" asm volatile ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "movq %rsp, %rdi" "\n" - "call " SYMBOL_STRING(cti_vm_throw) "\n" + "call " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" "addq $0x78, %rsp" "\n" "popq %rbx" "\n" "popq %r15" "\n" @@ -441,6 +517,7 @@ SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" asm volatile ( ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "addq $0x78, %rsp" "\n" "popq %rbx" "\n" @@ -452,7 +529,7 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ret" "\n" ); -#elif COMPILER(GCC) && PLATFORM_ARM_ARCH(7) +#elif COMPILER(GCC) && PLATFORM(ARM_THUMB2) #if USE(JIT_STUB_ARGUMENT_VA_LIST) #error "JIT_STUB_ARGUMENT_VA_LIST not supported on ARMv7." @@ -462,10 +539,11 @@ asm volatile ( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiTrampoline) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" - "sub sp, sp, #0x3c" "\n" + "sub sp, sp, #0x40" "\n" "str lr, [sp, #0x20]" "\n" "str r4, [sp, #0x24]" "\n" "str r5, [sp, #0x28]" "\n" @@ -480,7 +558,7 @@ SYMBOL_STRING(ctiTrampoline) ":" "\n" "ldr r5, [sp, #0x28]" "\n" "ldr r4, [sp, #0x24]" "\n" "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" + "add sp, sp, #0x40" "\n" "bx lr" "\n" ); @@ -488,16 +566,17 @@ asm volatile ( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "cpy r0, sp" "\n" - "bl " SYMBOL_STRING(cti_vm_throw) "\n" + "bl " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" "ldr r6, [sp, #0x2c]" "\n" "ldr r5, [sp, #0x28]" "\n" "ldr r4, [sp, #0x24]" "\n" "ldr lr, [sp, #0x20]" "\n" - "add sp, sp, #0x3c" "\n" + "add sp, sp, #0x40" "\n" "bx lr" "\n" ); @@ -505,8 +584,9 @@ asm volatile ( ".text" "\n" ".align 2" "\n" ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" ".thumb" "\n" -".thumb_func " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +".thumb_func " THUMB_FUNC_PARAM(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "ldr r6, [sp, #0x2c]" "\n" "ldr r5, [sp, #0x28]" "\n" @@ -516,44 +596,38 @@ SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" "bx lr" "\n" ); -#elif COMPILER(GCC) && PLATFORM(ARM) +#elif COMPILER(GCC) && PLATFORM(ARM_TRADITIONAL) asm volatile ( +".text\n" ".globl " SYMBOL_STRING(ctiTrampoline) "\n" +HIDE_SYMBOL(ctiTrampoline) "\n" SYMBOL_STRING(ctiTrampoline) ":" "\n" "stmdb sp!, {r1-r3}" "\n" "stmdb sp!, {r4-r8, lr}" "\n" - "mov r6, pc" "\n" - "add r6, r6, #40" "\n" - "sub sp, sp, #32" "\n" - "ldr r4, [sp, #60]" "\n" + "sub sp, sp, #36" "\n" + "mov r4, r2" "\n" "mov r5, #512" "\n" - // r0 contains the code - "add r8, pc, #4" "\n" - "str r8, [sp, #-4]!" "\n" + "mov lr, pc" "\n" "mov pc, r0" "\n" - "add sp, sp, #32" "\n" + "add sp, sp, #36" "\n" "ldmia sp!, {r4-r8, lr}" "\n" "add sp, sp, #12" "\n" "mov pc, lr" "\n" - - // the return instruction - "ldr pc, [sp], #4" "\n" ); asm volatile ( ".globl " SYMBOL_STRING(ctiVMThrowTrampoline) "\n" +HIDE_SYMBOL(ctiVMThrowTrampoline) "\n" SYMBOL_STRING(ctiVMThrowTrampoline) ":" "\n" "mov r0, sp" "\n" - "mov lr, r6" "\n" - "add r8, pc, #4" "\n" - "str r8, [sp, #-4]!" "\n" - "b " SYMBOL_STRING(cti_vm_throw) "\n" + "bl " SYMBOL_STRING_RELOCATION(cti_vm_throw) "\n" // Both has the same return sequence ".globl " SYMBOL_STRING(ctiOpThrowNotCaught) "\n" +HIDE_SYMBOL(ctiOpThrowNotCaught) "\n" SYMBOL_STRING(ctiOpThrowNotCaught) ":" "\n" - "add sp, sp, #32" "\n" + "add sp, sp, #36" "\n" "ldmia sp!, {r4-r8, lr}" "\n" "add sp, sp, #12" "\n" "mov pc, lr" "\n" @@ -636,7 +710,7 @@ JITThunks::JITThunks(JSGlobalData* globalData) { JIT::compileCTIMachineTrampolines(globalData, &m_executablePool, &m_ctiStringLengthTrampoline, &m_ctiVirtualCallLink, &m_ctiVirtualCall, &m_ctiNativeCallThunk); -#if PLATFORM_ARM_ARCH(7) +#if PLATFORM(ARM_THUMB2) // Unfortunate the arm compiler does not like the use of offsetof on JITStackFrame (since it contains non POD types), // and the OBJECT_OFFSETOF macro does not appear constantish enough for it to be happy with its use in COMPILE_ASSERT // macros. @@ -649,7 +723,7 @@ JITThunks::JITThunks(JSGlobalData* globalData) ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, callFrame) == 0x34); ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, exception) == 0x38); // The fifth argument is the first item already on the stack. - ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == 0x3c); + ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, enabledProfilerReference) == 0x40); ASSERT(OBJECT_OFFSETOF(struct JITStackFrame, thunkReturnAddress) == 0x1C); #endif @@ -673,7 +747,7 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co JSCell* baseCell = asCell(baseValue); Structure* structure = baseCell->structure(); - if (structure->isDictionary()) { + if (structure->isUncacheableDictionary()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); return; } @@ -688,11 +762,15 @@ NEVER_INLINE void JITThunks::tryCachePutByID(CallFrame* callFrame, CodeBlock* co // Structure transition, cache transition info if (slot.type() == PutPropertySlot::NewProperty) { - StructureChain* prototypeChain = structure->prototypeChain(callFrame); - if (!prototypeChain->isCacheable()) { + if (structure->isDictionary()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_put_by_id_generic)); return; } + + // put_by_id_transition checks the prototype chain for setters. + normalizePrototypeChain(callFrame, baseCell); + + StructureChain* prototypeChain = structure->prototypeChain(callFrame); stubInfo->initPutByIdTransition(structure->previousID(), structure, prototypeChain); JIT::compilePutByIdTransition(callFrame->scopeChain()->globalData, codeBlock, stubInfo, structure->previousID(), structure, slot.cachedOffset(), prototypeChain, returnAddress); return; @@ -737,7 +815,7 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co JSCell* baseCell = asCell(baseValue); Structure* structure = baseCell->structure(); - if (structure->isDictionary()) { + if (structure->isUncacheableDictionary()) { ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); return; } @@ -752,6 +830,11 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co return; } + if (structure->isDictionary()) { + ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); + return; + } + if (slot.slotBase() == structure->prototypeForLookup(callFrame)) { ASSERT(slot.slotBase().isObject()); @@ -760,25 +843,23 @@ NEVER_INLINE void JITThunks::tryCacheGetByID(CallFrame* callFrame, CodeBlock* co // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) - slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure())); + slotBaseObject->flattenDictionaryObject(); stubInfo->initGetByIdProto(structure, slotBaseObject->structure()); + ASSERT(!structure->isDictionary()); + ASSERT(!slotBaseObject->structure()->isDictionary()); JIT::compileGetByIdProto(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, slotBaseObject->structure(), slot.cachedOffset(), returnAddress); return; } - size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot); + size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase()); if (!count) { stubInfo->accessType = access_get_by_id_generic; return; } StructureChain* prototypeChain = structure->prototypeChain(callFrame); - if (!prototypeChain->isCacheable()) { - ctiPatchCallByReturnAddress(codeBlock, returnAddress, FunctionPtr(cti_op_get_by_id_generic)); - return; - } stubInfo->initGetByIdChain(structure, prototypeChain); JIT::compileGetByIdChain(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, structure, prototypeChain, count, slot.cachedOffset(), returnAddress); } @@ -876,7 +957,7 @@ static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalD } \ } while (0) -#if PLATFORM_ARM_ARCH(7) +#if PLATFORM(ARM_THUMB2) #define DEFINE_STUB_FUNCTION(rtype, op) \ extern "C" { \ @@ -886,8 +967,9 @@ static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalD ".text" "\n" \ ".align 2" "\n" \ ".globl " SYMBOL_STRING(cti_##op) "\n" \ + HIDE_SYMBOL(cti_##op) "\n" \ ".thumb" "\n" \ - ".thumb_func " SYMBOL_STRING(cti_##op) "\n" \ + ".thumb_func " THUMB_FUNC_PARAM(cti_##op) "\n" \ SYMBOL_STRING(cti_##op) ":" "\n" \ "str lr, [sp, #0x1c]" "\n" \ "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \ @@ -896,6 +978,30 @@ static NEVER_INLINE void throwStackOverflowError(CallFrame* callFrame, JSGlobalD ); \ rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) \ +#elif PLATFORM(ARM_TRADITIONAL) && COMPILER(GCC) + +#if USE(JSVALUE32_64) +#define THUNK_RETURN_ADDRESS_OFFSET 64 +#else +#define THUNK_RETURN_ADDRESS_OFFSET 32 +#endif + +COMPILE_ASSERT(offsetof(struct JITStackFrame, thunkReturnAddress) == THUNK_RETURN_ADDRESS_OFFSET, JITStackFrame_thunkReturnAddress_offset_mismatch); + +#define DEFINE_STUB_FUNCTION(rtype, op) \ + extern "C" { \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION); \ + }; \ + asm volatile ( \ + ".globl " SYMBOL_STRING(cti_##op) "\n" \ + SYMBOL_STRING(cti_##op) ":" "\n" \ + "str lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ + "bl " SYMBOL_STRING(JITStubThunked_##op) "\n" \ + "ldr lr, [sp, #" STRINGIZE_VALUE_OF(THUNK_RETURN_ADDRESS_OFFSET) "]" "\n" \ + "mov pc, lr" "\n" \ + ); \ + rtype JITStubThunked_##op(STUB_ARGS_DECLARATION) + #else #define DEFINE_STUB_FUNCTION(rtype, op) rtype JIT_STUB cti_##op(STUB_ARGS_DECLARATION) #endif @@ -939,19 +1045,15 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_add) bool leftIsString = v1.isString(); if (leftIsString && v2.isString()) { - RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep()); - if (UNLIKELY(!value)) { - throwOutOfMemoryError(callFrame); - VM_THROW_EXCEPTION(); - } - - return JSValue::encode(jsString(stackFrame.globalData, value.release())); + JSValue result = jsString(callFrame, asString(v1), asString(v2)); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(result); } if (rightIsNumber & leftIsString) { RefPtr<UString::Rep> value = v2.isInt32() ? - concatenate(asString(v1)->value().rep(), v2.asInt32()) : - concatenate(asString(v1)->value().rep(), right); + concatenate(asString(v1)->value(callFrame).rep(), v2.asInt32()) : + concatenate(asString(v1)->value(callFrame).rep(), right); if (UNLIKELY(!value)) { throwOutOfMemoryError(callFrame); @@ -1007,19 +1109,6 @@ DEFINE_STUB_FUNCTION(void, register_file_check) throwStackOverflowError(oldCallFrame, stackFrame.globalData, ReturnAddressPtr(oldCallFrame->returnPC()), STUB_RETURN_ADDRESS); } -DEFINE_STUB_FUNCTION(int, op_loop_if_less) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - JSValue src1 = stackFrame.args[0].jsValue(); - JSValue src2 = stackFrame.args[1].jsValue(); - CallFrame* callFrame = stackFrame.callFrame; - - bool result = jsLess(callFrame, src1, src2); - CHECK_FOR_EXCEPTION_AT_END(); - return result; -} - DEFINE_STUB_FUNCTION(int, op_loop_if_lesseq) { STUB_INIT_STACK_FRAME(stackFrame); @@ -1148,7 +1237,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) JSObject* slotBaseObject; if (baseValue.isCell() && slot.isCacheable() - && !(structure = asCell(baseValue)->structure())->isDictionary() + && !(structure = asCell(baseValue)->structure())->isUncacheableDictionary() && (slotBaseObject = asObject(slot.slotBase()))->getPropertySpecificValue(callFrame, ident, specific) && specific ) { @@ -1158,7 +1247,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) - slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure())); + slotBaseObject->flattenDictionaryObject(); // The result fetched should always be the callee! ASSERT(result == JSValue(callee)); @@ -1176,7 +1265,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_method_check) // for now. For now it performs a check on a special object on the global object only used for this // purpose. The object is in no way exposed, and as such the check will always pass. if (slot.slotBase() == baseValue) { - JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject()->methodCallDummy(), STUB_RETURN_ADDRESS); + JIT::patchMethodCallProto(codeBlock, methodCallLinkInfo, callee, structure, callFrame->scopeChain()->globalObject->methodCallDummy(), STUB_RETURN_ADDRESS); return JSValue::encode(result); } } @@ -1222,7 +1311,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_self_fail) if (baseValue.isCell() && slot.isCacheable() - && !asCell(baseValue)->structure()->isDictionary() + && !asCell(baseValue)->structure()->isUncacheableDictionary() && slot.slotBase() == baseValue) { CodeBlock* codeBlock = callFrame->codeBlock(); @@ -1308,10 +1397,11 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) if (slot.slotBase() == baseValue) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); else if (slot.slotBase() == asCell(baseValue)->structure()->prototypeForLookup(callFrame)) { + ASSERT(!asCell(baseValue)->structure()->isDictionary()); // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (slotBaseObject->structure()->isDictionary()) - slotBaseObject->setStructure(Structure::fromDictionaryTransition(slotBaseObject->structure())); + slotBaseObject->flattenDictionaryObject(); int listIndex; PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); @@ -1320,15 +1410,12 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_id_proto_list) if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_list_full)); - } else if (size_t count = countPrototypeChainEntriesAndCheckForProxies(callFrame, baseValue, slot)) { - StructureChain* protoChain = structure->prototypeChain(callFrame); - if (!protoChain->isCacheable()) { - ctiPatchCallByReturnAddress(codeBlock, STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_id_proto_fail)); - return JSValue::encode(result); - } - + } else if (size_t count = normalizePrototypeChain(callFrame, baseValue, slot.slotBase())) { + ASSERT(!asCell(baseValue)->structure()->isDictionary()); int listIndex; PolymorphicAccessStructureList* prototypeStructureList = getPolymorphicAccessStructureListSlot(stubInfo, listIndex); + + StructureChain* protoChain = structure->prototypeChain(callFrame); JIT::compileGetByIdChainList(callFrame->scopeChain()->globalData, callFrame, codeBlock, stubInfo, prototypeStructureList, listIndex, structure, protoChain, count, slot.cachedOffset()); if (listIndex == (POLYMORPHIC_LIST_CACHE_SIZE - 1)) @@ -1406,7 +1493,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_instanceof) // ECMA-262 15.3.5.3: // Throw an exception either if baseVal is not an object, or if it does not implement 'HasInstance' (i.e. is a function). - TypeInfo typeInfo(UnspecifiedType, 0); + TypeInfo typeInfo(UnspecifiedType); if (!baseVal.isObject() || !(typeInfo = asObject(baseVal)->structure()->typeInfo()).implementsHasInstance()) { CallFrame* callFrame = stackFrame.callFrame; CodeBlock* codeBlock = callFrame->codeBlock(); @@ -1467,7 +1554,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_func) { STUB_INIT_STACK_FRAME(stackFrame); - return stackFrame.args[0].funcDeclNode()->makeFunction(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); + return stackFrame.args[0].function()->make(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); } DEFINE_STUB_FUNCTION(void*, op_call_JSFunction) @@ -1481,11 +1568,11 @@ DEFINE_STUB_FUNCTION(void*, op_call_JSFunction) JSFunction* function = asFunction(stackFrame.args[0].jsValue()); ASSERT(!function->isHostFunction()); - FunctionBodyNode* body = function->body(); + FunctionExecutable* executable = function->jsExecutable(); ScopeChainNode* callDataScopeChain = function->scope().node(); - body->jitCode(callDataScopeChain); + executable->jitCode(stackFrame.callFrame, callDataScopeChain); - return &(body->generatedBytecode()); + return function; } DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) @@ -1493,8 +1580,9 @@ DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) STUB_INIT_STACK_FRAME(stackFrame); CallFrame* callFrame = stackFrame.callFrame; - CodeBlock* newCodeBlock = stackFrame.args[3].codeBlock(); - ASSERT(newCodeBlock->codeType() != NativeCode); + JSFunction* callee = asFunction(stackFrame.args[0].jsValue()); + ASSERT(!callee->isHostFunction()); + CodeBlock* newCodeBlock = &callee->jsExecutable()->generatedBytecode(); int argCount = stackFrame.args[2].int32(); ASSERT(argCount != newCodeBlock->m_numParameters); @@ -1531,7 +1619,7 @@ DEFINE_STUB_FUNCTION(VoidPtrPair, op_call_arityCheck) callFrame->setCallerFrame(oldCallFrame); } - RETURN_POINTER_PAIR(newCodeBlock, callFrame); + RETURN_POINTER_PAIR(callee, callFrame); } #if ENABLE(JIT_OPTIMIZE_CALL) @@ -1539,13 +1627,12 @@ DEFINE_STUB_FUNCTION(void*, vm_lazyLinkCall) { STUB_INIT_STACK_FRAME(stackFrame); JSFunction* callee = asFunction(stackFrame.args[0].jsValue()); - JITCode& jitCode = callee->body()->generatedJITCode(); + ExecutableBase* executable = callee->executable(); + JITCode& jitCode = executable->generatedJITCode(); CodeBlock* codeBlock = 0; - if (!callee->isHostFunction()) - codeBlock = &callee->body()->bytecode(callee->scope().node()); - else - codeBlock = &callee->body()->generatedBytecode(); + if (!executable->isHostFunction()) + codeBlock = &static_cast<FunctionExecutable*>(executable)->bytecode(stackFrame.callFrame, callee->scope().node()); CallLinkInfo* callLinkInfo = &stackFrame.callFrame->callerFrame()->codeBlock()->getCallLinkInfo(stackFrame.args[1].returnAddress()); if (!callLinkInfo->seenOnce()) @@ -1561,7 +1648,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_push_activation) { STUB_INIT_STACK_FRAME(stackFrame); - JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast<FunctionBodyNode*>(stackFrame.callFrame->codeBlock()->ownerNode())); + JSActivation* activation = new (stackFrame.globalData) JSActivation(stackFrame.callFrame, static_cast<FunctionExecutable*>(stackFrame.callFrame->codeBlock()->ownerExecutable())); stackFrame.callFrame->setScopeChain(stackFrame.callFrame->scopeChain()->copy()->push(activation)); return activation; } @@ -1732,7 +1819,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_construct_JSConstruct) if (stackFrame.args[3].jsValue().isObject()) structure = asObject(stackFrame.args[3].jsValue())->inheritorID(); else - structure = constructor->scope().node()->globalObject()->emptyObjectStructure(); + structure = constructor->scope().node()->globalObject->emptyObjectStructure(); return new (stackFrame.globalData) JSObject(structure); } @@ -1793,7 +1880,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val) } else if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) { // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_string)); - result = asString(baseValue)->getIndex(stackFrame.globalData, i); + result = asString(baseValue)->getIndex(callFrame, i); } else if (isJSByteArray(globalData, baseValue) && asByteArray(baseValue)->canAccessIndex(i)) { // All fast byte array accesses are safe from exceptions so return immediately to avoid exception checks. ctiPatchCallByReturnAddress(callFrame->codeBlock(), STUB_RETURN_ADDRESS, FunctionPtr(cti_op_get_by_val_byte_array)); @@ -1824,7 +1911,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_get_by_val_string) if (LIKELY(subscript.isUInt32())) { uint32_t i = subscript.asUInt32(); if (isJSString(globalData, baseValue) && asString(baseValue)->canGetIndex(i)) - result = asString(baseValue)->getIndex(stackFrame.globalData, i); + result = asString(baseValue)->getIndex(callFrame, i); else { result = baseValue.get(callFrame, i); if (!isJSString(globalData, baseValue)) @@ -1936,28 +2023,6 @@ DEFINE_STUB_FUNCTION(void, op_put_by_val) CHECK_FOR_EXCEPTION_AT_END(); } -DEFINE_STUB_FUNCTION(void, op_put_by_val_array) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - CallFrame* callFrame = stackFrame.callFrame; - JSValue baseValue = stackFrame.args[0].jsValue(); - int i = stackFrame.args[1].int32(); - JSValue value = stackFrame.args[2].jsValue(); - - ASSERT(isJSArray(stackFrame.globalData, baseValue)); - - if (LIKELY(i >= 0)) - asArray(baseValue)->JSArray::put(callFrame, i, value); - else { - Identifier property(callFrame, UString::from(i)); - PutPropertySlot slot; - baseValue.put(callFrame, property, value, slot); - } - - CHECK_FOR_EXCEPTION_AT_END(); -} - DEFINE_STUB_FUNCTION(void, op_put_by_val_byte_array) { STUB_INIT_STACK_FRAME(stackFrame); @@ -2011,19 +2076,6 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_lesseq) return JSValue::encode(result); } -DEFINE_STUB_FUNCTION(int, op_loop_if_true) -{ - STUB_INIT_STACK_FRAME(stackFrame); - - JSValue src1 = stackFrame.args[0].jsValue(); - - CallFrame* callFrame = stackFrame.callFrame; - - bool result = src1.toBoolean(callFrame); - CHECK_FOR_EXCEPTION_AT_END(); - return result; -} - DEFINE_STUB_FUNCTION(int, op_load_varargs) { STUB_INIT_STACK_FRAME(stackFrame); @@ -2042,7 +2094,7 @@ DEFINE_STUB_FUNCTION(int, op_load_varargs) stackFrame.globalData->exception = createStackOverflowError(callFrame); VM_THROW_EXCEPTION(); } - int32_t expectedParams = callFrame->callee()->body()->parameterCount(); + int32_t expectedParams = callFrame->callee()->jsExecutable()->parameterCount(); int32_t inplaceArgs = min(providedParams, expectedParams); Register* inplaceArgsDst = callFrame->registers() + argsOffset; @@ -2182,7 +2234,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_global) PropertySlot slot(globalObject); if (globalObject->getPropertySlot(callFrame, ident, slot)) { JSValue result = slot.getValue(callFrame, ident); - if (slot.isCacheable() && !globalObject->structure()->isDictionary() && slot.slotBase() == globalObject) { + if (slot.isCacheable() && !globalObject->structure()->isUncacheableDictionary() && slot.slotBase() == globalObject) { GlobalResolveInfo& globalResolveInfo = callFrame->codeBlock()->globalResolveInfo(globalResolveInfoIndex); if (globalResolveInfo.structure) globalResolveInfo.structure->deref(); @@ -2358,38 +2410,33 @@ DEFINE_STUB_FUNCTION(int, op_eq) if (src1.isNull()) return src2.isCell() && asCell(src2)->structure()->typeInfo().masqueradesAsUndefined(); - ASSERT(src1.isCell()); - JSCell* cell1 = asCell(src1); if (cell1->isString()) { if (src2.isInt32()) - return static_cast<JSString*>(cell1)->value().toDouble() == src2.asInt32(); + return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asInt32(); if (src2.isDouble()) - return static_cast<JSString*>(cell1)->value().toDouble() == src2.asDouble(); + return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == src2.asDouble(); if (src2.isTrue()) - return static_cast<JSString*>(cell1)->value().toDouble() == 1.0; + return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 1.0; if (src2.isFalse()) - return static_cast<JSString*>(cell1)->value().toDouble() == 0.0; + return static_cast<JSString*>(cell1)->value(stackFrame.callFrame).toDouble() == 0.0; - ASSERT(src2.isCell()); JSCell* cell2 = asCell(src2); if (cell2->isString()) - return static_cast<JSString*>(cell1)->value() == static_cast<JSString*>(cell2)->value(); + return static_cast<JSString*>(cell1)->value(stackFrame.callFrame) == static_cast<JSString*>(cell2)->value(stackFrame.callFrame); - ASSERT(cell2->isObject()); - src2 = static_cast<JSObject*>(cell2)->toPrimitive(stackFrame.callFrame); + src2 = asObject(cell2)->toPrimitive(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); goto start; } - ASSERT(cell1->isObject()); if (src2.isObject()) - return static_cast<JSObject*>(cell1) == asObject(src2); - src1 = static_cast<JSObject*>(cell1)->toPrimitive(stackFrame.callFrame); + return asObject(cell1) == asObject(src2); + src1 = asObject(cell1)->toPrimitive(stackFrame.callFrame); CHECK_FOR_EXCEPTION(); goto start; } @@ -2403,7 +2450,7 @@ DEFINE_STUB_FUNCTION(int, op_eq_strings) ASSERT(string1->isString()); ASSERT(string2->isString()); - return string1->value() == string2->value(); + return string1->value(stackFrame.callFrame) == string2->value(stackFrame.callFrame); } #else // USE(JSVALUE32_64) @@ -2517,8 +2564,24 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_resolve_with_base) DEFINE_STUB_FUNCTION(JSObject*, op_new_func_exp) { STUB_INIT_STACK_FRAME(stackFrame); + CallFrame* callFrame = stackFrame.callFrame; - return stackFrame.args[0].funcExprNode()->makeFunction(stackFrame.callFrame, stackFrame.callFrame->scopeChain()); + FunctionExecutable* function = stackFrame.args[0].function(); + JSFunction* func = function->make(callFrame, callFrame->scopeChain()); + + /* + 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 (!function->name().isNull()) { + JSStaticScopeObject* functionScopeObject = new (callFrame) JSStaticScopeObject(callFrame, function->name(), func, ReadOnly | DontDelete); + func->scope().push(functionScopeObject); + } + + return func; } DEFINE_STUB_FUNCTION(EncodedJSValue, op_mod) @@ -2624,7 +2687,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_call_eval) Register* newCallFrame = callFrame->registers() + registerOffset; Register* argv = newCallFrame - RegisterFile::CallFrameHeaderSize - argCount; JSValue thisValue = argv[0].jsValue(); - JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject(); + JSGlobalObject* globalObject = callFrame->scopeChain()->globalObject; if (thisValue == globalObject && funcVal == globalObject->evalFunction()) { JSValue exceptionValue; @@ -2655,7 +2718,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_throw) if (!handler) { *stackFrame.exception = exceptionValue; - STUB_SET_RETURN_ADDRESS(reinterpret_cast<void*>(ctiOpThrowNotCaught)); + STUB_SET_RETURN_ADDRESS(FunctionPtr(ctiOpThrowNotCaught).value()); return JSValue::encode(jsNull()); } @@ -2670,18 +2733,22 @@ DEFINE_STUB_FUNCTION(JSPropertyNameIterator*, op_get_pnames) { STUB_INIT_STACK_FRAME(stackFrame); - return JSPropertyNameIterator::create(stackFrame.callFrame, stackFrame.args[0].jsValue()); + CallFrame* callFrame = stackFrame.callFrame; + JSObject* o = stackFrame.args[0].jsObject(); + Structure* structure = o->structure(); + JSPropertyNameIterator* jsPropertyNameIterator = structure->enumerationCache(); + if (!jsPropertyNameIterator || jsPropertyNameIterator->cachedPrototypeChain() != structure->prototypeChain(callFrame)) + jsPropertyNameIterator = JSPropertyNameIterator::create(callFrame, o); + return jsPropertyNameIterator; } -DEFINE_STUB_FUNCTION(EncodedJSValue, op_next_pname) +DEFINE_STUB_FUNCTION(int, has_property) { STUB_INIT_STACK_FRAME(stackFrame); - JSPropertyNameIterator* it = stackFrame.args[0].propertyNameIterator(); - JSValue temp = it->next(stackFrame.callFrame); - if (!temp) - it->invalidate(); - return JSValue::encode(temp); + JSObject* base = stackFrame.args[0].jsObject(); + JSString* property = stackFrame.args[1].jsString(); + return base->hasProperty(stackFrame.callFrame, Identifier(stackFrame.callFrame, property->value(stackFrame.callFrame))); } DEFINE_STUB_FUNCTION(JSObject*, op_push_scope) @@ -2758,7 +2825,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_stricteq) JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); - return JSValue::encode(jsBoolean(JSValue::strictEqual(src1, src2))); + return JSValue::encode(jsBoolean(JSValue::strictEqual(stackFrame.callFrame, src1, src2))); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_primitive) @@ -2772,7 +2839,9 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_strcat) { STUB_INIT_STACK_FRAME(stackFrame); - return JSValue::encode(concatenateStrings(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32())); + JSValue result = jsString(stackFrame.callFrame, &stackFrame.callFrame->registers()[stackFrame.args[0].int32()], stackFrame.args[1].int32()); + CHECK_FOR_EXCEPTION_AT_END(); + return JSValue::encode(result); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq) @@ -2782,7 +2851,7 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, op_nstricteq) JSValue src1 = stackFrame.args[0].jsValue(); JSValue src2 = stackFrame.args[1].jsValue(); - return JSValue::encode(jsBoolean(!JSValue::strictEqual(src1, src2))); + return JSValue::encode(jsBoolean(!JSValue::strictEqual(stackFrame.callFrame, src1, src2))); } DEFINE_STUB_FUNCTION(EncodedJSValue, op_to_jsnumber) @@ -2891,7 +2960,7 @@ DEFINE_STUB_FUNCTION(void*, op_switch_char) void* result = codeBlock->characterSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { - UString::Rep* value = asString(scrutinee)->value().rep(); + UString::Rep* value = asString(scrutinee)->value(callFrame).rep(); if (value->size() == 1) result = codeBlock->characterSwitchJumpTable(tableIndex).ctiForValue(value->data()[0]).executableAddress(); } @@ -2911,7 +2980,7 @@ DEFINE_STUB_FUNCTION(void*, op_switch_string) void* result = codeBlock->stringSwitchJumpTable(tableIndex).ctiDefault.executableAddress(); if (scrutinee.isString()) { - UString::Rep* value = asString(scrutinee)->value().rep(); + UString::Rep* value = asString(scrutinee)->value(callFrame).rep(); result = codeBlock->stringSwitchJumpTable(tableIndex).ctiForValue(value).executableAddress(); } @@ -2978,7 +3047,7 @@ DEFINE_STUB_FUNCTION(JSObject*, op_new_error) unsigned bytecodeOffset = stackFrame.args[2].int32(); unsigned lineNumber = codeBlock->lineNumberForBytecodeOffset(callFrame, bytecodeOffset); - return Error::create(callFrame, static_cast<ErrorType>(type), message.toString(callFrame), lineNumber, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + return Error::create(callFrame, static_cast<ErrorType>(type), message.toString(callFrame), lineNumber, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); } DEFINE_STUB_FUNCTION(void, op_debug) @@ -3022,6 +3091,14 @@ DEFINE_STUB_FUNCTION(EncodedJSValue, vm_throw) return JSValue::encode(exceptionValue); } +DEFINE_STUB_FUNCTION(EncodedJSValue, to_object) +{ + STUB_INIT_STACK_FRAME(stackFrame); + + CallFrame* callFrame = stackFrame.callFrame; + return JSValue::encode(stackFrame.args[0].jsValue().toObject(callFrame)); +} + } // namespace JSC #endif // ENABLE(JIT) diff --git a/JavaScriptCore/jit/JITStubs.h b/JavaScriptCore/jit/JITStubs.h index 8f02435..f71dc9a 100644 --- a/JavaScriptCore/jit/JITStubs.h +++ b/JavaScriptCore/jit/JITStubs.h @@ -42,6 +42,7 @@ namespace JSC { class CodeBlock; class ExecutablePool; + class FunctionExecutable; class Identifier; class JSGlobalData; class JSGlobalData; @@ -53,8 +54,6 @@ namespace JSC { class PropertySlot; class PutPropertySlot; class RegisterFile; - class FuncDeclNode; - class FuncExprNode; class JSGlobalObject; class RegExp; @@ -64,11 +63,11 @@ namespace JSC { int32_t asInt32; JSValue jsValue() { return JSValue::decode(asEncodedJSValue); } + JSObject* jsObject() { return static_cast<JSObject*>(asPointer); } Identifier& identifier() { return *static_cast<Identifier*>(asPointer); } int32_t int32() { return asInt32; } CodeBlock* codeBlock() { return static_cast<CodeBlock*>(asPointer); } - FuncDeclNode* funcDeclNode() { return static_cast<FuncDeclNode*>(asPointer); } - FuncExprNode* funcExprNode() { return static_cast<FuncExprNode*>(asPointer); } + FunctionExecutable* function() { return static_cast<FunctionExecutable*>(asPointer); } RegExp* regExp() { return static_cast<RegExp*>(asPointer); } JSPropertyNameIterator* propertyNameIterator() { return static_cast<JSPropertyNameIterator*>(asPointer); } JSGlobalObject* globalObject() { return static_cast<JSGlobalObject*>(asPointer); } @@ -131,7 +130,7 @@ namespace JSC { #if COMPILER(MSVC) #pragma pack(pop) #endif // COMPILER(MSVC) -#elif PLATFORM_ARM_ARCH(7) +#elif PLATFORM(ARM_THUMB2) struct JITStackFrame { void* reserved; // Unused JITStubArg args[6]; @@ -151,17 +150,21 @@ namespace JSC { CallFrame* callFrame; JSValue* exception; + void* padding2; + // These arguments passed on the stack. Profiler** enabledProfilerReference; JSGlobalData* globalData; ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; } }; -#elif PLATFORM(ARM) +#elif PLATFORM(ARM_TRADITIONAL) struct JITStackFrame { JITStubArg padding; // Unused JITStubArg args[7]; + ReturnAddressPtr thunkReturnAddress; + void* preservedR4; void* preservedR5; void* preservedR6; @@ -172,16 +175,20 @@ namespace JSC { RegisterFile* registerFile; CallFrame* callFrame; JSValue* exception; + + // These arguments passed on the stack. Profiler** enabledProfilerReference; JSGlobalData* globalData; // When JIT code makes a call, it pushes its return address just below the rest of the stack. - ReturnAddressPtr* returnAddressSlot() { return reinterpret_cast<ReturnAddressPtr*>(this) - 1; } + ReturnAddressPtr* returnAddressSlot() { return &thunkReturnAddress; } }; #else #error "JITStackFrame not defined for this platform." #endif +#define JITSTACKFRAME_ARGS_INDEX (OBJECT_OFFSETOF(JITStackFrame, args) / sizeof(void*)) + #if USE(JIT_STUB_ARGUMENT_VA_LIST) #define STUB_ARGS_DECLARATION void* args, ... #define STUB_ARGS (reinterpret_cast<void**>(vl_args) - 1) @@ -285,7 +292,6 @@ extern "C" { EncodedJSValue JIT_STUB cti_op_mod(STUB_ARGS_DECLARATION); EncodedJSValue JIT_STUB cti_op_mul(STUB_ARGS_DECLARATION); EncodedJSValue JIT_STUB cti_op_negate(STUB_ARGS_DECLARATION); - EncodedJSValue JIT_STUB cti_op_next_pname(STUB_ARGS_DECLARATION); EncodedJSValue JIT_STUB cti_op_not(STUB_ARGS_DECLARATION); EncodedJSValue JIT_STUB cti_op_nstricteq(STUB_ARGS_DECLARATION); EncodedJSValue JIT_STUB cti_op_post_dec(STUB_ARGS_DECLARATION); @@ -307,6 +313,7 @@ extern "C" { EncodedJSValue JIT_STUB cti_op_typeof(STUB_ARGS_DECLARATION); EncodedJSValue JIT_STUB cti_op_urshift(STUB_ARGS_DECLARATION); EncodedJSValue JIT_STUB cti_vm_throw(STUB_ARGS_DECLARATION); + EncodedJSValue JIT_STUB cti_to_object(STUB_ARGS_DECLARATION); JSObject* JIT_STUB cti_op_construct_JSConstruct(STUB_ARGS_DECLARATION); JSObject* JIT_STUB cti_op_new_array(STUB_ARGS_DECLARATION); JSObject* JIT_STUB cti_op_new_error(STUB_ARGS_DECLARATION); @@ -328,10 +335,9 @@ extern "C" { int JIT_STUB cti_op_jlesseq(STUB_ARGS_DECLARATION); int JIT_STUB cti_op_jtrue(STUB_ARGS_DECLARATION); int JIT_STUB cti_op_load_varargs(STUB_ARGS_DECLARATION); - int JIT_STUB cti_op_loop_if_less(STUB_ARGS_DECLARATION); int JIT_STUB cti_op_loop_if_lesseq(STUB_ARGS_DECLARATION); - int JIT_STUB cti_op_loop_if_true(STUB_ARGS_DECLARATION); int JIT_STUB cti_timeout_check(STUB_ARGS_DECLARATION); + int JIT_STUB cti_has_property(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_create_arguments(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_create_arguments_no_params(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_debug(STUB_ARGS_DECLARATION); @@ -345,7 +351,6 @@ extern "C" { void JIT_STUB cti_op_put_by_id_generic(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_index(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_val(STUB_ARGS_DECLARATION); - void JIT_STUB cti_op_put_by_val_array(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_by_val_byte_array(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_getter(STUB_ARGS_DECLARATION); void JIT_STUB cti_op_put_setter(STUB_ARGS_DECLARATION); diff --git a/JavaScriptCore/jsc.cpp b/JavaScriptCore/jsc.cpp index 92b1e58..b6bc0aa 100644 --- a/JavaScriptCore/jsc.cpp +++ b/JavaScriptCore/jsc.cpp @@ -24,10 +24,12 @@ #include "BytecodeGenerator.h" #include "Completion.h" +#include "CurrentTime.h" #include "InitializeThreading.h" #include "JSArray.h" #include "JSFunction.h" #include "JSLock.h" +#include "JSString.h" #include "PrototypeFunction.h" #include "SamplingTool.h" #include <math.h> @@ -118,53 +120,23 @@ public: 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 + double m_startTime; + double m_stopTime; }; 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 + m_startTime = currentTime(); } 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 + m_stopTime = currentTime(); } 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 + return static_cast<long>((m_stopTime - m_startTime) * 1000); } class GlobalObject : public JSGlobalObject { @@ -389,11 +361,8 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr if (dump) BytecodeGenerator::setDumpsGeneratedCode(true); -#if ENABLE(OPCODE_SAMPLING) - Interpreter* interpreter = globalObject->globalData()->interpreter; - interpreter->setSampler(new SamplingTool(interpreter)); - interpreter->sampler()->setup(); -#endif + JSGlobalData* globalData = globalObject->globalData(); + #if ENABLE(SAMPLING_FLAGS) SamplingFlags::start(); #endif @@ -410,9 +379,7 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr fileName = "[Command Line]"; } -#if ENABLE(SAMPLING_THREAD) - SamplingThread::start(); -#endif + globalData->startSampling(); Completion completion = evaluate(globalObject->globalExec(), globalObject->globalScopeChain(), makeSource(script, fileName)); success = success && completion.complType() != Throw; @@ -423,20 +390,14 @@ static bool runWithScripts(GlobalObject* globalObject, const Vector<Script>& scr printf("End: %s\n", completion.value().toString(globalObject->globalExec()).ascii()); } -#if ENABLE(SAMPLING_THREAD) - SamplingThread::stop(); -#endif - + globalData->stopSampling(); globalObject->globalExec()->clearException(); } #if ENABLE(SAMPLING_FLAGS) SamplingFlags::stop(); #endif -#if ENABLE(OPCODE_SAMPLING) - interpreter->sampler()->dump(globalObject->globalExec()); - delete interpreter->sampler(); -#endif + globalData->dumpSampleData(globalObject->globalExec()); #if ENABLE(SAMPLING_COUNTERS) AbstractSamplingCounter::dump(); #endif diff --git a/JavaScriptCore/jsc.pro b/JavaScriptCore/jsc.pro index ba880ff..9bcf08b 100644 --- a/JavaScriptCore/jsc.pro +++ b/JavaScriptCore/jsc.pro @@ -23,9 +23,13 @@ CONFIG(debug, debug|release) { OBJECTS_DIR_WTR = $$OBJECTS_DIR$${QMAKE_DIR_SEP} include($$PWD/JavaScriptCore.pri) -lessThan(QT_MINOR_VERSION, 4) { - DEFINES += QT_BEGIN_NAMESPACE="" QT_END_NAMESPACE="" -} - *-g++*:QMAKE_CXXFLAGS_RELEASE -= -O2 *-g++*:QMAKE_CXXFLAGS_RELEASE += -O3 + +symbian { + TARGET.CAPABILITY = ReadUserData WriteUserData NetworkServices +} + +mac { + LIBS_PRIVATE += -framework AppKit +}
\ No newline at end of file diff --git a/JavaScriptCore/os-win32/stdbool.h b/JavaScriptCore/os-win32/stdbool.h index 8e7bace..fc8ee28 100644 --- a/JavaScriptCore/os-win32/stdbool.h +++ b/JavaScriptCore/os-win32/stdbool.h @@ -21,8 +21,8 @@ #ifndef STDBOOL_WIN32_H #define STDBOOL_WIN32_H -#if !PLATFORM(WIN_OS) -#error "This stdbool.h file should only be compiled under Windows" +#if !COMPILER(MSVC) +#error "This stdbool.h file should only be compiled with MSVC" #endif #ifndef __cplusplus diff --git a/JavaScriptCore/os-win32/stdint.h b/JavaScriptCore/os-win32/stdint.h index efab2ae..1d8787e 100644 --- a/JavaScriptCore/os-win32/stdint.h +++ b/JavaScriptCore/os-win32/stdint.h @@ -23,10 +23,11 @@ #include <wtf/Platform.h> -/* This file emulates enough of stdint.h on Windows to make JavaScriptCore and WebCore compile. */ +/* This file emulates enough of stdint.h on Windows to make JavaScriptCore and WebCore + compile using MSVC which does not ship with the stdint.h header. */ -#if !PLATFORM(WIN_OS) -#error "This stdint.h file should only be compiled under Windows" +#if !COMPILER(MSVC) +#error "This stdint.h file should only be compiled with MSVC" #endif #include <limits.h> diff --git a/JavaScriptCore/parser/Grammar.y b/JavaScriptCore/parser/Grammar.y index 354c786..6d953df 100644 --- a/JavaScriptCore/parser/Grammar.y +++ b/JavaScriptCore/parser/Grammar.y @@ -25,18 +25,13 @@ #include "config.h" -#include <string.h> -#include <stdlib.h> -#include "JSValue.h" #include "JSObject.h" -#include "NodeConstructors.h" -#include "Lexer.h" #include "JSString.h" -#include "JSGlobalData.h" -#include "CommonIdentifiers.h" +#include "Lexer.h" +#include "NodeConstructors.h" #include "NodeInfo.h" -#include "Parser.h" -#include <wtf/FastMalloc.h> +#include <stdlib.h> +#include <string.h> #include <wtf/MathExtras.h> #define YYMALLOC fastMalloc @@ -45,46 +40,43 @@ #define YYMAXDEPTH 10000 #define YYENABLE_NLS 0 -/* default values for bison */ +// Default values for bison. #define YYDEBUG 0 // Set to 1 to debug a parse error. #define jscyydebug 0 // Set to 1 to debug a parse error. #if !PLATFORM(DARWIN) - // avoid triggering warnings in older bison +// Avoid triggering warnings in older bison by not setting this on the Darwin platform. +// FIXME: Is this still needed? #define YYERROR_VERBOSE #endif -int jscyylex(void* lvalp, void* llocp, void* globalPtr); int jscyyerror(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(*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) +#define AUTO_SEMICOLON do { if (!allowAutomaticSemicolon(*GLOBAL_DATA->lexer, yychar)) YYABORT; } while (0) using namespace JSC; using namespace std; -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* combineCommaNodes(void*, ExpressionNode* list, ExpressionNode* init); +static ExpressionNode* makeAssignNode(JSGlobalData*, ExpressionNode* left, Operator, ExpressionNode* right, bool leftHasAssignments, bool rightHasAssignments, int start, int divot, int end); +static ExpressionNode* makePrefixNode(JSGlobalData*, ExpressionNode*, Operator, int start, int divot, int end); +static ExpressionNode* makePostfixNode(JSGlobalData*, ExpressionNode*, Operator, int start, int divot, int end); +static PropertyNode* makeGetterOrSetterPropertyNode(JSGlobalData*, const Identifier& getOrSet, const Identifier& name, ParameterNode*, FunctionBodyNode*, const SourceCode&); +static ExpressionNodeInfo makeFunctionCallNode(JSGlobalData*, ExpressionNodeInfo function, ArgumentsNodeInfo, int start, int divot, int end); +static ExpressionNode* makeTypeOfNode(JSGlobalData*, ExpressionNode*); +static ExpressionNode* makeDeleteNode(JSGlobalData*, ExpressionNode*, int start, int divot, int end); +static ExpressionNode* makeNegateNode(JSGlobalData*, ExpressionNode*); +static NumberNode* makeNumberNode(JSGlobalData*, double); +static ExpressionNode* makeBitwiseNotNode(JSGlobalData*, ExpressionNode*); +static ExpressionNode* makeMultNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); +static ExpressionNode* makeDivNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); +static ExpressionNode* makeAddNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); +static ExpressionNode* makeSubNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); +static ExpressionNode* makeLeftShiftNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); +static ExpressionNode* makeRightShiftNode(JSGlobalData*, ExpressionNode* left, ExpressionNode* right, bool rightHasAssignments); +static StatementNode* makeVarStatementNode(JSGlobalData*, ExpressionNode*); +static ExpressionNode* combineCommaNodes(JSGlobalData*, ExpressionNode* list, ExpressionNode* init); #if COMPILER(MSVC) @@ -97,17 +89,17 @@ static ExpressionNode* combineCommaNodes(void*, ExpressionNode* list, Expression #define YYPARSE_PARAM globalPtr #define YYLEX_PARAM globalPtr -template <typename T> NodeDeclarationInfo<T> createNodeDeclarationInfo(T node, ParserArenaData<DeclarationStacks::VarStack>* varDecls, - ParserArenaData<DeclarationStacks::FunctionStack>* funcDecls, - CodeFeatures info, - int numConstants) +template <typename T> inline NodeDeclarationInfo<T> createNodeDeclarationInfo(T node, + ParserArenaData<DeclarationStacks::VarStack>* varDecls, + ParserArenaData<DeclarationStacks::FunctionStack>* funcDecls, + CodeFeatures info, int numConstants) { 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) +template <typename T> inline NodeInfo<T> createNodeInfo(T node, CodeFeatures info, int numConstants) { ASSERT((info & ~AllFeatures) == 0); NodeInfo<T> result = { node, info, numConstants }; @@ -133,21 +125,20 @@ template <typename T> inline T mergeDeclarationLists(T decls1, T decls2) return decls1; } -static void appendToVarDeclarationList(void* globalPtr, ParserArenaData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs) +static inline void appendToVarDeclarationList(JSGlobalData* globalData, ParserArenaData<DeclarationStacks::VarStack>*& varDecls, const Identifier& ident, unsigned attrs) { if (!varDecls) - varDecls = new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>; - - varDecls->data.append(make_pair(ident, attrs)); + varDecls = new (globalData) ParserArenaData<DeclarationStacks::VarStack>; + varDecls->data.append(make_pair(&ident, attrs)); } -static inline void appendToVarDeclarationList(void* globalPtr, ParserArenaData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl) +static inline void appendToVarDeclarationList(JSGlobalData* globalData, ParserArenaData<DeclarationStacks::VarStack>*& varDecls, ConstDeclNode* decl) { unsigned attrs = DeclarationStacks::IsConstant; if (decl->hasInitializer()) attrs |= DeclarationStacks::HasInitializer; - appendToVarDeclarationList(globalPtr, varDecls, decl->ident(), attrs); + appendToVarDeclarationList(globalData, varDecls, decl->ident(), attrs); } %} @@ -155,7 +146,7 @@ static inline void appendToVarDeclarationList(void* globalPtr, ParserArenaData<D %union { int intValue; double doubleValue; - Identifier* ident; + const Identifier* ident; // expression subtrees ExpressionNodeInfo expressionNode; @@ -184,6 +175,20 @@ static inline void appendToVarDeclarationList(void* globalPtr, ParserArenaData<D Operator op; } +%{ + +template <typename T> inline void setStatementLocation(StatementNode* statement, const T& start, const T& end) +{ + statement->setLoc(start.first_line, end.last_line); +} + +static inline void setExceptionLocation(ThrowableExpressionData* node, unsigned start, unsigned divot, unsigned end) +{ + node->setExceptionSourceCode(divot, divot - start, end - divot); +} + +%} + %start Program /* literals */ @@ -291,21 +296,25 @@ Literal: | NUMBER { $$ = createNodeInfo<ExpressionNode*>(makeNumberNode(GLOBAL_DATA, $1), 0, 1); } | STRING { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) StringNode(GLOBAL_DATA, *$1), 0, 1); } | '/' /* regexp */ { - Lexer& l = *LEXER; - if (!l.scanRegExp()) + Lexer& l = *GLOBAL_DATA->lexer; + const Identifier* pattern; + const Identifier* flags; + if (!l.scanRegExp(pattern, flags)) YYABORT; - RegExpNode* node = new (GLOBAL_DATA) 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); + RegExpNode* node = new (GLOBAL_DATA) RegExpNode(GLOBAL_DATA, *pattern, *flags); + int size = pattern->size() + 2; // + 2 for the two /'s + setExceptionLocation(node, @1.first_column, @1.first_column + size, @1.first_column + size); $$ = createNodeInfo<ExpressionNode*>(node, 0, 0); } | DIVEQUAL /* regexp with /= */ { - Lexer& l = *LEXER; - if (!l.scanRegExp()) + Lexer& l = *GLOBAL_DATA->lexer; + const Identifier* pattern; + const Identifier* flags; + if (!l.scanRegExp(pattern, flags, '=')) YYABORT; - RegExpNode* node = new (GLOBAL_DATA) 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); + RegExpNode* node = new (GLOBAL_DATA) RegExpNode(GLOBAL_DATA, *pattern, *flags); + int size = pattern->size() + 2; // + 2 for the two /'s + setExceptionLocation(node, @1.first_column, @1.first_column + size, @1.first_column + size); $$ = createNodeInfo<ExpressionNode*>(node, 0, 0); } ; @@ -313,14 +322,14 @@ Literal: Property: IDENT ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new (GLOBAL_DATA) PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } | STRING ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new (GLOBAL_DATA) PropertyNode(GLOBAL_DATA, *$1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } - | NUMBER ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new (GLOBAL_DATA) 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; } + | NUMBER ':' AssignmentExpr { $$ = createNodeInfo<PropertyNode*>(new (GLOBAL_DATA) PropertyNode(GLOBAL_DATA, $1, $3.m_node, PropertyNode::Constant), $3.m_features, $3.m_numConstants); } + | IDENT IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(GLOBAL_DATA, *$1, *$2, 0, $6, GLOBAL_DATA->lexer->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); setStatementLocation($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); + $$ = createNodeInfo<PropertyNode*>(makeGetterOrSetterPropertyNode(GLOBAL_DATA, *$1, *$2, $4.m_node.head, $7, GLOBAL_DATA->lexer->sourceCode($6, $8, @6.first_line)), $4.m_features | ClosureFeature, 0); if ($4.m_features & ArgumentsFeature) $7->setUsesArguments(); - DBG($7, @6, @8); + setStatementLocation($7, @6, @8); if (!$$.m_node) YYABORT; } @@ -385,15 +394,15 @@ MemberExpr: PrimaryExpr | FunctionExpr { $$ = createNodeInfo<ExpressionNode*>($1.m_node, $1.m_features, $1.m_numConstants); } | MemberExpr '[' Expr ']' { BracketAccessorNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(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 (GLOBAL_DATA) DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); + setExceptionLocation(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 (GLOBAL_DATA) NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column); + setExceptionLocation(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); } ; @@ -401,15 +410,15 @@ MemberExpr: MemberExprNoBF: PrimaryExprNoBrace | MemberExprNoBF '[' Expr ']' { BracketAccessorNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(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 (GLOBAL_DATA) DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); + setExceptionLocation(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 (GLOBAL_DATA) NewExprNode(GLOBAL_DATA, $2.m_node, $3.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @3.last_column); + setExceptionLocation(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); } ; @@ -417,7 +426,7 @@ MemberExprNoBF: NewExpr: MemberExpr | NEW NewExpr { NewExprNode* node = new (GLOBAL_DATA) NewExprNode(GLOBAL_DATA, $2.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants); } ; @@ -425,32 +434,32 @@ NewExpr: NewExprNoBF: MemberExprNoBF | NEW NewExpr { NewExprNode* node = new (GLOBAL_DATA) NewExprNode(GLOBAL_DATA, $2.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); $$ = createNodeInfo<ExpressionNode*>(node, $2.m_features, $2.m_numConstants); } ; CallExpr: - 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); } + MemberExpr Arguments { $$ = makeFunctionCallNode(GLOBAL_DATA, $1, $2, @1.first_column, @1.last_column, @2.last_column); } + | CallExpr Arguments { $$ = makeFunctionCallNode(GLOBAL_DATA, $1, $2, @1.first_column, @1.last_column, @2.last_column); } | CallExpr '[' Expr ']' { BracketAccessorNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(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 (GLOBAL_DATA) DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); + setExceptionLocation(node, @1.first_column, @1.last_column, @3.last_column); $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); } ; CallExprNoBF: - 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); } + MemberExprNoBF Arguments { $$ = makeFunctionCallNode(GLOBAL_DATA, $1, $2, @1.first_column, @1.last_column, @2.last_column); } + | CallExprNoBF Arguments { $$ = makeFunctionCallNode(GLOBAL_DATA, $1, $2, @1.first_column, @1.last_column, @2.last_column); } | CallExprNoBF '[' Expr ']' { BracketAccessorNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(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 (GLOBAL_DATA) DotAccessorNode(GLOBAL_DATA, $1.m_node, *$3); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @3.last_column); + setExceptionLocation(node, @1.first_column, @1.last_column, @3.last_column); $$ = createNodeInfo<ExpressionNode*>(node, $1.m_features, $1.m_numConstants); } ; @@ -568,10 +577,10 @@ RelationalExpr: | RelationalExpr LE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) 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 (GLOBAL_DATA) 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 (GLOBAL_DATA) 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); + setExceptionLocation(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 (GLOBAL_DATA) 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); + setExceptionLocation(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); } ; @@ -583,7 +592,7 @@ RelationalExprNoIn: | RelationalExprNoIn GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) 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 { InstanceOfNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(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); } ; @@ -595,11 +604,11 @@ RelationalExprNoBF: | RelationalExprNoBF GE ShiftExpr { $$ = createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) 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 { InstanceOfNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(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 (GLOBAL_DATA) 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); + setExceptionLocation(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); } ; @@ -810,17 +819,17 @@ Statement: ; Block: - OPENBRACE CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BlockNode(GLOBAL_DATA, 0), 0, 0, 0, 0); - DBG($$.m_node, @1, @2); } - | OPENBRACE SourceElements CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BlockNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); - DBG($$.m_node, @1, @3); } + OPENBRACE CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BlockNode(GLOBAL_DATA, 0), 0, 0, 0, 0); + setStatementLocation($$.m_node, @1, @2); } + | OPENBRACE SourceElements CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BlockNode(GLOBAL_DATA, $2.m_node), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); + setStatementLocation($$.m_node, @1, @3); } ; VariableStatement: 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); } + setStatementLocation($$.m_node, @1, @3); } | 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); + setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; } ; @@ -833,7 +842,7 @@ VariableDeclarationList: $$.m_numConstants = 0; } | IDENT Initializer { AssignResolveNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(node, @1.first_column, @2.first_column + 1, @2.last_column); $$.m_node = node; $$.m_varDeclarations = new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>; appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer); @@ -851,7 +860,7 @@ VariableDeclarationList: } | VariableDeclarationList ',' IDENT Initializer { AssignResolveNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(node, @3.first_column, @4.first_column + 1, @4.last_column); $$.m_node = combineCommaNodes(GLOBAL_DATA, $1.m_node, node); $$.m_varDeclarations = $1.m_varDeclarations; appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer); @@ -870,7 +879,7 @@ VariableDeclarationListNoIn: $$.m_numConstants = 0; } | IDENT InitializerNoIn { AssignResolveNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(node, @1.first_column, @2.first_column + 1, @2.last_column); $$.m_node = node; $$.m_varDeclarations = new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::VarStack>; appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$1, DeclarationStacks::HasInitializer); @@ -888,7 +897,7 @@ VariableDeclarationListNoIn: } | VariableDeclarationListNoIn ',' IDENT InitializerNoIn { AssignResolveNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(node, @3.first_column, @4.first_column + 1, @4.last_column); $$.m_node = combineCommaNodes(GLOBAL_DATA, $1.m_node, node); $$.m_varDeclarations = $1.m_varDeclarations; appendToVarDeclarationList(GLOBAL_DATA, $$.m_varDeclarations, *$3, DeclarationStacks::HasInitializer); @@ -900,10 +909,10 @@ VariableDeclarationListNoIn: ConstStatement: CONSTTOKEN ConstDeclarationList ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ConstStatementNode(GLOBAL_DATA, $2.m_node.head), $2.m_varDeclarations, $2.m_funcDeclarations, $2.m_features, $2.m_numConstants); - DBG($$.m_node, @1, @3); } + setStatementLocation($$.m_node, @1, @3); } | CONSTTOKEN ConstDeclarationList error { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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; } + setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; } ; ConstDeclarationList: @@ -945,36 +954,36 @@ EmptyStatement: ExprStatement: ExprNoBF ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants); - DBG($$.m_node, @1, @2); } + setStatementLocation($$.m_node, @1, @2); } | ExprNoBF error { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ExprStatementNode(GLOBAL_DATA, $1.m_node), 0, 0, $1.m_features, $1.m_numConstants); - DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } + setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; } ; IfStatement: IF '(' Expr ')' Statement %prec IF_WITHOUT_ELSE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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); } + setStatementLocation($$.m_node, @1, @4); } | IF '(' Expr ')' Statement ELSE Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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); } + setStatementLocation($$.m_node, @1, @4); } ; IterationStatement: DO Statement WHILE '(' Expr ')' ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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); } + setStatementLocation($$.m_node, @1, @3); } | DO Statement WHILE '(' Expr ')' error { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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. + setStatementLocation($$.m_node, @1, @3); } // Always performs automatic semicolon insertion. | WHILE '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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); } + setStatementLocation($$.m_node, @1, @4); } | FOR '(' ExprNoInOpt ';' ExprOpt ';' ExprOpt ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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); + setStatementLocation($$.m_node, @1, @8); } | FOR '(' VAR VariableDeclarationListNoIn ';' ExprOpt ';' ExprOpt ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) ForNode(GLOBAL_DATA, $4.m_node, $6.m_node, $8.m_node, $10.m_node, true), @@ -982,30 +991,30 @@ IterationStatement: 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); } + setStatementLocation($$.m_node, @1, @9); } | FOR '(' LeftHandSideExpr INTOKEN Expr ')' Statement { ForInNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(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); + setStatementLocation($$.m_node, @1, @6); } | FOR '(' VAR IDENT INTOKEN Expr ')' Statement { ForInNode *forIn = new (GLOBAL_DATA) 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); + setExceptionLocation(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); } + setStatementLocation($$.m_node, @1, @7); } | FOR '(' VAR IDENT InitializerNoIn INTOKEN Expr ')' Statement { ForInNode *forIn = new (GLOBAL_DATA) 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); + setExceptionLocation(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); } + setStatementLocation($$.m_node, @1, @8); } ; ExprOpt: @@ -1020,63 +1029,63 @@ ExprNoInOpt: ContinueStatement: CONTINUE ';' { ContinueNode* node = new (GLOBAL_DATA) ContinueNode(GLOBAL_DATA); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); + setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column); $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); - DBG($$.m_node, @1, @2); } + setStatementLocation($$.m_node, @1, @2); } | CONTINUE error { ContinueNode* node = new (GLOBAL_DATA) ContinueNode(GLOBAL_DATA); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); + setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column); $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); - DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } + setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; } | CONTINUE IDENT ';' { ContinueNode* node = new (GLOBAL_DATA) ContinueNode(GLOBAL_DATA, *$2); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); - DBG($$.m_node, @1, @3); } + setStatementLocation($$.m_node, @1, @3); } | CONTINUE IDENT error { ContinueNode* node = new (GLOBAL_DATA) ContinueNode(GLOBAL_DATA, *$2); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); - DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } + setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; } ; BreakStatement: BREAK ';' { BreakNode* node = new (GLOBAL_DATA) 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); } + setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @2); } | BREAK error { BreakNode* node = new (GLOBAL_DATA) BreakNode(GLOBAL_DATA); - SET_EXCEPTION_LOCATION(node, @1.first_column, @1.last_column, @1.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BreakNode(GLOBAL_DATA), 0, 0, 0, 0); DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } + setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BreakNode(GLOBAL_DATA), 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; } | BREAK IDENT ';' { BreakNode* node = new (GLOBAL_DATA) 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); } + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @3); } | BREAK IDENT error { BreakNode* node = new (GLOBAL_DATA) BreakNode(GLOBAL_DATA, *$2); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); - $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BreakNode(GLOBAL_DATA, *$2), 0, 0, 0, 0); DBG($$.m_node, @1, @2); AUTO_SEMICOLON; } + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) BreakNode(GLOBAL_DATA, *$2), 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; } ; ReturnStatement: RETURN ';' { ReturnNode* node = new (GLOBAL_DATA) 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); } + setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @2); } | RETURN error { ReturnNode* node = new (GLOBAL_DATA) 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; } + setExceptionLocation(node, @1.first_column, @1.last_column, @1.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, 0, 0); setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; } | RETURN Expr ';' { ReturnNode* node = new (GLOBAL_DATA) 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); } + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); setStatementLocation($$.m_node, @1, @3); } | RETURN Expr error { ReturnNode* node = new (GLOBAL_DATA) 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; } + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; } ; WithStatement: WITH '(' Expr ')' Statement { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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); } + setStatementLocation($$.m_node, @1, @4); } ; SwitchStatement: SWITCH '(' Expr ')' CaseBlock { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) 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); } + setStatementLocation($$.m_node, @1, @4); } ; CaseBlock: @@ -1090,7 +1099,7 @@ CaseBlock: ; CaseClausesOpt: -/* nothing */ { $$.m_node.head = 0; $$.m_node.tail = 0; $$.m_varDeclarations = 0; $$.m_funcDeclarations = 0; $$.m_features = 0; $$.m_numConstants = 0; } + /* nothing */ { $$.m_node.head = 0; $$.m_node.tail = 0; $$.m_varDeclarations = 0; $$.m_funcDeclarations = 0; $$.m_features = 0; $$.m_numConstants = 0; } | CaseClauses ; @@ -1122,18 +1131,18 @@ DefaultClause: LabelledStatement: IDENT ':' Statement { LabelNode* node = new (GLOBAL_DATA) LabelNode(GLOBAL_DATA, *$1, $3.m_node); - SET_EXCEPTION_LOCATION(node, @1.first_column, @2.last_column, @2.last_column); + setExceptionLocation(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 ';' { ThrowNode* node = new (GLOBAL_DATA) 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); + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); setStatementLocation($$.m_node, @1, @2); } | THROW Expr error { ThrowNode* node = new (GLOBAL_DATA) 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; + setExceptionLocation(node, @1.first_column, @2.last_column, @2.last_column); + $$ = createNodeDeclarationInfo<StatementNode*>(node, 0, 0, $2.m_features, $2.m_numConstants); setStatementLocation($$.m_node, @1, @2); AUTO_SEMICOLON; } ; @@ -1143,57 +1152,57 @@ TryStatement: mergeDeclarationLists($2.m_funcDeclarations, $4.m_funcDeclarations), $2.m_features | $4.m_features, $2.m_numConstants + $4.m_numConstants); - DBG($$.m_node, @1, @2); } + setStatementLocation($$.m_node, @1, @2); } | TRY Block CATCH '(' IDENT ')' Block { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) TryNode(GLOBAL_DATA, $2.m_node, *$5, ($7.m_features & EvalFeature) != 0, $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); } + setStatementLocation($$.m_node, @1, @2); } | TRY Block CATCH '(' IDENT ')' Block FINALLY Block { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) TryNode(GLOBAL_DATA, $2.m_node, *$5, ($7.m_features & EvalFeature) != 0, $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); } + setStatementLocation($$.m_node, @1, @2); } ; DebuggerStatement: DEBUGGER ';' { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0); - DBG($$.m_node, @1, @2); } + setStatementLocation($$.m_node, @1, @2); } | DEBUGGER error { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) DebuggerStatementNode(GLOBAL_DATA), 0, 0, 0, 0); - DBG($$.m_node, @1, @1); AUTO_SEMICOLON; } + setStatementLocation($$.m_node, @1, @1); AUTO_SEMICOLON; } ; FunctionDeclaration: - FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new FuncDeclNode(GLOBAL_DATA, *$2, $6, LEXER->sourceCode($5, $7, @5.first_line)), 0, new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::FunctionStack>, ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | ClosureFeature, 0); DBG($6, @5, @7); $$.m_funcDeclarations->data.append(static_cast<FuncDeclNode*>($$.m_node)); } + FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) FuncDeclNode(GLOBAL_DATA, *$2, $6, GLOBAL_DATA->lexer->sourceCode($5, $7, @5.first_line)), 0, new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::FunctionStack>, ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | ClosureFeature, 0); setStatementLocation($6, @5, @7); $$.m_funcDeclarations->data.append(static_cast<FuncDeclNode*>($$.m_node)->body()); } | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE - { - $$ = createNodeDeclarationInfo<StatementNode*>(new FuncDeclNode(GLOBAL_DATA, *$2, $7, LEXER->sourceCode($6, $8, @6.first_line), $4.m_node.head), 0, new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::FunctionStack>, ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features | ClosureFeature, 0); + { + $$ = createNodeDeclarationInfo<StatementNode*>(new (GLOBAL_DATA) FuncDeclNode(GLOBAL_DATA, *$2, $7, GLOBAL_DATA->lexer->sourceCode($6, $8, @6.first_line), $4.m_node.head), 0, new (GLOBAL_DATA) ParserArenaData<DeclarationStacks::FunctionStack>, ((*$2 == GLOBAL_DATA->propertyNames->arguments) ? ArgumentsFeature : 0) | $4.m_features | ClosureFeature, 0); if ($4.m_features & ArgumentsFeature) - $7->setUsesArguments(); - DBG($7, @6, @8); - $$.m_funcDeclarations->data.append(static_cast<FuncDeclNode*>($$.m_node)); + $7->setUsesArguments(); + setStatementLocation($7, @6, @8); + $$.m_funcDeclarations->data.append(static_cast<FuncDeclNode*>($$.m_node)->body()); } ; FunctionExpr: - 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) + FUNCTION '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new (GLOBAL_DATA) FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $5, GLOBAL_DATA->lexer->sourceCode($4, $6, @4.first_line)), ClosureFeature, 0); setStatementLocation($5, @4, @6); } + | FUNCTION '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE + { + $$ = createNodeInfo(new (GLOBAL_DATA) FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, $6, GLOBAL_DATA->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); + setStatementLocation($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); + | FUNCTION IDENT '(' ')' OPENBRACE FunctionBody CLOSEBRACE { $$ = createNodeInfo(new (GLOBAL_DATA) FuncExprNode(GLOBAL_DATA, *$2, $6, GLOBAL_DATA->lexer->sourceCode($5, $7, @5.first_line)), ClosureFeature, 0); setStatementLocation($6, @5, @7); } + | FUNCTION IDENT '(' FormalParameterList ')' OPENBRACE FunctionBody CLOSEBRACE + { + $$ = createNodeInfo(new (GLOBAL_DATA) FuncExprNode(GLOBAL_DATA, *$2, $7, GLOBAL_DATA->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); + setStatementLocation($7, @6, @8); } ; @@ -1241,8 +1250,8 @@ Literal_NoNode: | FALSETOKEN | NUMBER { } | STRING { } - | '/' /* regexp */ { Lexer& l = *LEXER; if (!l.scanRegExp()) YYABORT; } - | DIVEQUAL /* regexp with /= */ { Lexer& l = *LEXER; if (!l.scanRegExp()) YYABORT; } + | '/' /* regexp */ { if (!GLOBAL_DATA->lexer->skipRegExp()) YYABORT; } + | DIVEQUAL /* regexp with /= */ { if (!GLOBAL_DATA->lexer->skipRegExp()) YYABORT; } ; Property_NoNode: @@ -1824,26 +1833,28 @@ SourceElements_NoNode: %% -static ExpressionNode* makeAssignNode(void* globalPtr, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end) +#undef GLOBAL_DATA + +static ExpressionNode* makeAssignNode(JSGlobalData* globalData, ExpressionNode* loc, Operator op, ExpressionNode* expr, bool locHasAssignments, bool exprHasAssignments, int start, int divot, int end) { if (!loc->isLocation()) - return new (GLOBAL_DATA) AssignErrorNode(GLOBAL_DATA, loc, op, expr, divot, divot - start, end - divot); + return new (globalData) AssignErrorNode(globalData, loc, op, expr, divot, divot - start, end - divot); if (loc->isResolveNode()) { ResolveNode* resolve = static_cast<ResolveNode*>(loc); if (op == OpEqual) { - AssignResolveNode* node = new (GLOBAL_DATA) AssignResolveNode(GLOBAL_DATA, resolve->identifier(), expr, exprHasAssignments); - SET_EXCEPTION_LOCATION(node, start, divot, end); + AssignResolveNode* node = new (globalData) AssignResolveNode(globalData, resolve->identifier(), expr, exprHasAssignments); + setExceptionLocation(node, start, divot, end); return node; } else - return new (GLOBAL_DATA) ReadModifyResolveNode(GLOBAL_DATA, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); + return new (globalData) ReadModifyResolveNode(globalData, resolve->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); } if (loc->isBracketAccessorNode()) { BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(loc); if (op == OpEqual) - return new (GLOBAL_DATA) AssignBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot()); + return new (globalData) AssignBracketNode(globalData, bracket->base(), bracket->subscript(), expr, locHasAssignments, exprHasAssignments, bracket->divot(), bracket->divot() - start, end - bracket->divot()); else { - ReadModifyBracketNode* node = new (GLOBAL_DATA) ReadModifyBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot); + ReadModifyBracketNode* node = new (globalData) ReadModifyBracketNode(globalData, bracket->base(), bracket->subscript(), op, expr, locHasAssignments, exprHasAssignments, divot, divot - start, end - divot); node->setSubexpressionInfo(bracket->divot(), bracket->endOffset()); return node; } @@ -1851,117 +1862,117 @@ static ExpressionNode* makeAssignNode(void* globalPtr, ExpressionNode* loc, Oper ASSERT(loc->isDotAccessorNode()); DotAccessorNode* dot = static_cast<DotAccessorNode*>(loc); if (op == OpEqual) - return new (GLOBAL_DATA) AssignDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot()); + return new (globalData) AssignDotNode(globalData, dot->base(), dot->identifier(), expr, exprHasAssignments, dot->divot(), dot->divot() - start, end - dot->divot()); - ReadModifyDotNode* node = new (GLOBAL_DATA) ReadModifyDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); + ReadModifyDotNode* node = new (globalData) ReadModifyDotNode(globalData, dot->base(), dot->identifier(), op, expr, exprHasAssignments, divot, divot - start, end - divot); node->setSubexpressionInfo(dot->divot(), dot->endOffset()); return node; } -static ExpressionNode* makePrefixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end) +static ExpressionNode* makePrefixNode(JSGlobalData* globalData, ExpressionNode* expr, Operator op, int start, int divot, int end) { if (!expr->isLocation()) - return new (GLOBAL_DATA) PrefixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot); + return new (globalData) PrefixErrorNode(globalData, expr, op, divot, divot - start, end - divot); if (expr->isResolveNode()) { ResolveNode* resolve = static_cast<ResolveNode*>(expr); - return new (GLOBAL_DATA) PrefixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot); + return new (globalData) PrefixResolveNode(globalData, resolve->identifier(), op, divot, divot - start, end - divot); } if (expr->isBracketAccessorNode()) { BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); - PrefixBracketNode* node = new (GLOBAL_DATA) PrefixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot); + PrefixBracketNode* node = new (globalData) PrefixBracketNode(globalData, 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); - PrefixDotNode* node = new (GLOBAL_DATA) PrefixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); + PrefixDotNode* node = new (globalData) PrefixDotNode(globalData, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); node->setSubexpressionInfo(dot->divot(), dot->startOffset()); return node; } -static ExpressionNode* makePostfixNode(void* globalPtr, ExpressionNode* expr, Operator op, int start, int divot, int end) +static ExpressionNode* makePostfixNode(JSGlobalData* globalData, ExpressionNode* expr, Operator op, int start, int divot, int end) { if (!expr->isLocation()) - return new (GLOBAL_DATA) PostfixErrorNode(GLOBAL_DATA, expr, op, divot, divot - start, end - divot); + return new (globalData) PostfixErrorNode(globalData, expr, op, divot, divot - start, end - divot); if (expr->isResolveNode()) { ResolveNode* resolve = static_cast<ResolveNode*>(expr); - return new (GLOBAL_DATA) PostfixResolveNode(GLOBAL_DATA, resolve->identifier(), op, divot, divot - start, end - divot); + return new (globalData) PostfixResolveNode(globalData, resolve->identifier(), op, divot, divot - start, end - divot); } if (expr->isBracketAccessorNode()) { BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); - PostfixBracketNode* node = new (GLOBAL_DATA) PostfixBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), op, divot, divot - start, end - divot); + PostfixBracketNode* node = new (globalData) PostfixBracketNode(globalData, 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); - PostfixDotNode* node = new (GLOBAL_DATA) PostfixDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); + PostfixDotNode* node = new (globalData) PostfixDotNode(globalData, dot->base(), dot->identifier(), op, divot, divot - start, end - divot); node->setSubexpressionInfo(dot->divot(), dot->endOffset()); return node; } -static ExpressionNodeInfo makeFunctionCallNode(void* globalPtr, ExpressionNodeInfo func, ArgumentsNodeInfo args, int start, int divot, int end) +static ExpressionNodeInfo makeFunctionCallNode(JSGlobalData* globalData, ExpressionNodeInfo func, ArgumentsNodeInfo args, int start, int divot, int end) { 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 (GLOBAL_DATA) FunctionCallValueNode(GLOBAL_DATA, func.m_node, args.m_node, divot, divot - start, end - divot), features, numConstants); + return createNodeInfo<ExpressionNode*>(new (globalData) FunctionCallValueNode(globalData, 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 (GLOBAL_DATA) EvalFunctionCallNode(GLOBAL_DATA, args.m_node, divot, divot - start, end - divot), EvalFeature | features, numConstants); - return createNodeInfo<ExpressionNode*>(new (GLOBAL_DATA) FunctionCallResolveNode(GLOBAL_DATA, identifier, args.m_node, divot, divot - start, end - divot), features, numConstants); + if (identifier == globalData->propertyNames->eval) + return createNodeInfo<ExpressionNode*>(new (globalData) EvalFunctionCallNode(globalData, args.m_node, divot, divot - start, end - divot), EvalFeature | features, numConstants); + return createNodeInfo<ExpressionNode*>(new (globalData) FunctionCallResolveNode(globalData, identifier, args.m_node, divot, divot - start, end - divot), features, numConstants); } if (func.m_node->isBracketAccessorNode()) { BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(func.m_node); - FunctionCallBracketNode* node = new (GLOBAL_DATA) FunctionCallBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), args.m_node, divot, divot - start, end - divot); + FunctionCallBracketNode* node = new (globalData) FunctionCallBracketNode(globalData, 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.m_node->isDotAccessorNode()); DotAccessorNode* dot = static_cast<DotAccessorNode*>(func.m_node); FunctionCallDotNode* node; - if (dot->identifier() == GLOBAL_DATA->propertyNames->call) - node = new (GLOBAL_DATA) CallFunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot); - else if (dot->identifier() == GLOBAL_DATA->propertyNames->apply) - node = new (GLOBAL_DATA) ApplyFunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot); + if (dot->identifier() == globalData->propertyNames->call) + node = new (globalData) CallFunctionCallDotNode(globalData, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot); + else if (dot->identifier() == globalData->propertyNames->apply) + node = new (globalData) ApplyFunctionCallDotNode(globalData, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot); else - node = new (GLOBAL_DATA) FunctionCallDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), args.m_node, divot, divot - start, end - divot); + node = new (globalData) FunctionCallDotNode(globalData, 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(void* globalPtr, ExpressionNode* expr) +static ExpressionNode* makeTypeOfNode(JSGlobalData* globalData, ExpressionNode* expr) { if (expr->isResolveNode()) { ResolveNode* resolve = static_cast<ResolveNode*>(expr); - return new (GLOBAL_DATA) TypeOfResolveNode(GLOBAL_DATA, resolve->identifier()); + return new (globalData) TypeOfResolveNode(globalData, resolve->identifier()); } - return new (GLOBAL_DATA) TypeOfValueNode(GLOBAL_DATA, expr); + return new (globalData) TypeOfValueNode(globalData, expr); } -static ExpressionNode* makeDeleteNode(void* globalPtr, ExpressionNode* expr, int start, int divot, int end) +static ExpressionNode* makeDeleteNode(JSGlobalData* globalData, ExpressionNode* expr, int start, int divot, int end) { if (!expr->isLocation()) - return new (GLOBAL_DATA) DeleteValueNode(GLOBAL_DATA, expr); + return new (globalData) DeleteValueNode(globalData, expr); if (expr->isResolveNode()) { ResolveNode* resolve = static_cast<ResolveNode*>(expr); - return new (GLOBAL_DATA) DeleteResolveNode(GLOBAL_DATA, resolve->identifier(), divot, divot - start, end - divot); + return new (globalData) DeleteResolveNode(globalData, resolve->identifier(), divot, divot - start, end - divot); } if (expr->isBracketAccessorNode()) { BracketAccessorNode* bracket = static_cast<BracketAccessorNode*>(expr); - return new (GLOBAL_DATA) DeleteBracketNode(GLOBAL_DATA, bracket->base(), bracket->subscript(), divot, divot - start, end - divot); + return new (globalData) DeleteBracketNode(globalData, bracket->base(), bracket->subscript(), divot, divot - start, end - divot); } ASSERT(expr->isDotAccessorNode()); DotAccessorNode* dot = static_cast<DotAccessorNode*>(expr); - return new (GLOBAL_DATA) DeleteDotNode(GLOBAL_DATA, dot->base(), dot->identifier(), divot, divot - start, end - divot); + return new (globalData) DeleteDotNode(globalData, dot->base(), dot->identifier(), divot, divot - start, end - divot); } -static PropertyNode* makeGetterOrSetterPropertyNode(void* globalPtr, const Identifier& getOrSet, const Identifier& name, ParameterNode* params, FunctionBodyNode* body, const SourceCode& source) +static PropertyNode* makeGetterOrSetterPropertyNode(JSGlobalData* globalData, const Identifier& getOrSet, const Identifier& name, ParameterNode* params, FunctionBodyNode* body, const SourceCode& source) { PropertyNode::Type type; if (getOrSet == "get") @@ -1970,10 +1981,10 @@ static PropertyNode* makeGetterOrSetterPropertyNode(void* globalPtr, const Ident type = PropertyNode::Setter; else return 0; - return new (GLOBAL_DATA) PropertyNode(GLOBAL_DATA, name, new FuncExprNode(GLOBAL_DATA, GLOBAL_DATA->propertyNames->nullIdentifier, body, source, params), type); + return new (globalData) PropertyNode(globalData, name, new (globalData) FuncExprNode(globalData, globalData->propertyNames->nullIdentifier, body, source, params), type); } -static ExpressionNode* makeNegateNode(void* globalPtr, ExpressionNode* n) +static ExpressionNode* makeNegateNode(JSGlobalData* globalData, ExpressionNode* n) { if (n->isNumber()) { NumberNode* number = static_cast<NumberNode*>(n); @@ -1984,92 +1995,92 @@ static ExpressionNode* makeNegateNode(void* globalPtr, ExpressionNode* n) } } - return new (GLOBAL_DATA) NegateNode(GLOBAL_DATA, n); + return new (globalData) NegateNode(globalData, n); } -static NumberNode* makeNumberNode(void* globalPtr, double d) +static NumberNode* makeNumberNode(JSGlobalData* globalData, double d) { - return new (GLOBAL_DATA) NumberNode(GLOBAL_DATA, d); + return new (globalData) NumberNode(globalData, d); } -static ExpressionNode* makeBitwiseNotNode(void* globalPtr, ExpressionNode* expr) +static ExpressionNode* makeBitwiseNotNode(JSGlobalData* globalData, ExpressionNode* expr) { if (expr->isNumber()) - return makeNumberNode(globalPtr, ~toInt32(static_cast<NumberNode*>(expr)->value())); - return new (GLOBAL_DATA) BitwiseNotNode(GLOBAL_DATA, expr); + return makeNumberNode(globalData, ~toInt32(static_cast<NumberNode*>(expr)->value())); + return new (globalData) BitwiseNotNode(globalData, expr); } -static ExpressionNode* makeMultNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +static ExpressionNode* makeMultNode(JSGlobalData* globalData, 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 makeNumberNode(globalData, static_cast<NumberNode*>(expr1)->value() * static_cast<NumberNode*>(expr2)->value()); if (expr1->isNumber() && static_cast<NumberNode*>(expr1)->value() == 1) - return new (GLOBAL_DATA) UnaryPlusNode(GLOBAL_DATA, expr2); + return new (globalData) UnaryPlusNode(globalData, expr2); if (expr2->isNumber() && static_cast<NumberNode*>(expr2)->value() == 1) - return new (GLOBAL_DATA) UnaryPlusNode(GLOBAL_DATA, expr1); + return new (globalData) UnaryPlusNode(globalData, expr1); - return new (GLOBAL_DATA) MultNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); + return new (globalData) MultNode(globalData, expr1, expr2, rightHasAssignments); } -static ExpressionNode* makeDivNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +static ExpressionNode* makeDivNode(JSGlobalData* globalData, 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 (GLOBAL_DATA) DivNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); + return makeNumberNode(globalData, static_cast<NumberNode*>(expr1)->value() / static_cast<NumberNode*>(expr2)->value()); + return new (globalData) DivNode(globalData, expr1, expr2, rightHasAssignments); } -static ExpressionNode* makeAddNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +static ExpressionNode* makeAddNode(JSGlobalData* globalData, 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 (GLOBAL_DATA) AddNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); + return makeNumberNode(globalData, static_cast<NumberNode*>(expr1)->value() + static_cast<NumberNode*>(expr2)->value()); + return new (globalData) AddNode(globalData, expr1, expr2, rightHasAssignments); } -static ExpressionNode* makeSubNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +static ExpressionNode* makeSubNode(JSGlobalData* globalData, 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 (GLOBAL_DATA) SubNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); + return makeNumberNode(globalData, static_cast<NumberNode*>(expr1)->value() - static_cast<NumberNode*>(expr2)->value()); + return new (globalData) SubNode(globalData, expr1, expr2, rightHasAssignments); } -static ExpressionNode* makeLeftShiftNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +static ExpressionNode* makeLeftShiftNode(JSGlobalData* globalData, 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 (GLOBAL_DATA) LeftShiftNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); + return makeNumberNode(globalData, toInt32(static_cast<NumberNode*>(expr1)->value()) << (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f)); + return new (globalData) LeftShiftNode(globalData, expr1, expr2, rightHasAssignments); } -static ExpressionNode* makeRightShiftNode(void* globalPtr, ExpressionNode* expr1, ExpressionNode* expr2, bool rightHasAssignments) +static ExpressionNode* makeRightShiftNode(JSGlobalData* globalData, 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 (GLOBAL_DATA) RightShiftNode(GLOBAL_DATA, expr1, expr2, rightHasAssignments); + return makeNumberNode(globalData, toInt32(static_cast<NumberNode*>(expr1)->value()) >> (toUInt32(static_cast<NumberNode*>(expr2)->value()) & 0x1f)); + return new (globalData) RightShiftNode(globalData, expr1, expr2, rightHasAssignments); } -/* called by yyparse on error */ -int yyerror(const char *) +// Called by yyparse on error. +int yyerror(const char*) { return 1; } -/* may we automatically insert a semicolon ? */ +// May we automatically insert a semicolon? static bool allowAutomaticSemicolon(Lexer& lexer, int yychar) { return yychar == CLOSEBRACE || yychar == 0 || lexer.prevTerminator(); } -static ExpressionNode* combineCommaNodes(void* globalPtr, ExpressionNode* list, ExpressionNode* init) +static ExpressionNode* combineCommaNodes(JSGlobalData* globalData, ExpressionNode* list, ExpressionNode* init) { if (!list) return init; @@ -2077,17 +2088,15 @@ static ExpressionNode* combineCommaNodes(void* globalPtr, ExpressionNode* list, static_cast<CommaNode*>(list)->append(init); return list; } - return new (GLOBAL_DATA) CommaNode(GLOBAL_DATA, list, init); + return new (globalData) CommaNode(globalData, 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(void* globalPtr, ExpressionNode* expr) +static StatementNode* makeVarStatementNode(JSGlobalData* globalData, ExpressionNode* expr) { if (!expr) - return new (GLOBAL_DATA) EmptyStatementNode(GLOBAL_DATA); - return new (GLOBAL_DATA) VarStatementNode(GLOBAL_DATA, expr); + return new (globalData) EmptyStatementNode(globalData); + return new (globalData) VarStatementNode(globalData, expr); } - -#undef GLOBAL_DATA diff --git a/JavaScriptCore/parser/Lexer.cpp b/JavaScriptCore/parser/Lexer.cpp index 8e89c18..9148230 100644 --- a/JavaScriptCore/parser/Lexer.cpp +++ b/JavaScriptCore/parser/Lexer.cpp @@ -39,19 +39,10 @@ using namespace Unicode; // We can't specify the namespace in yacc's C output, so do it here instead. using namespace JSC; -#ifndef KDE_USE_FINAL #include "Grammar.h" -#endif - #include "Lookup.h" #include "Lexer.lut.h" -// A bridge for yacc from the C world to the C++ world. -int jscyylex(void* lvalp, void* llocp, void* globalData) -{ - return static_cast<JSGlobalData*>(globalData)->lexer->lex(lvalp, llocp); -} - namespace JSC { static const UChar byteOrderMark = 0xFEFF; @@ -141,8 +132,10 @@ ALWAYS_INLINE void Lexer::shift4() m_code += 4; } -void Lexer::setCode(const SourceCode& source) +void Lexer::setCode(const SourceCode& source, ParserArena& arena) { + m_arena = &arena.identifierArena(); + m_lineNumber = source.firstLine(); m_delimited = false; m_lastToken = -1; @@ -204,10 +197,9 @@ void Lexer::shiftLineTerminator() ++m_lineNumber; } -ALWAYS_INLINE Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length) +ALWAYS_INLINE const Identifier* Lexer::makeIdentifier(const UChar* characters, size_t length) { - m_identifiers.append(Identifier(m_globalData, characters, length)); - return &m_identifiers.last(); + return &m_arena->makeIdentifier(m_globalData, characters, length); } inline bool Lexer::lastTokenWasRestrKeyword() const @@ -908,48 +900,110 @@ returnError: return -1; } -bool Lexer::scanRegExp() +bool Lexer::scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix) { ASSERT(m_buffer16.isEmpty()); bool lastWasEscape = false; bool inBrackets = false; + if (patternPrefix) { + ASSERT(!isLineTerminator(patternPrefix)); + ASSERT(patternPrefix != '/'); + ASSERT(patternPrefix != '['); + record16(patternPrefix); + } + while (true) { - if (isLineTerminator(m_current) || m_current == -1) - return false; - if (m_current != '/' || lastWasEscape || inBrackets) { - // 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); + int current = m_current; + + if (isLineTerminator(current) || current == -1) { m_buffer16.resize(0); - shift1(); - break; + return false; } + shift1(); + + if (current == '/' && !lastWasEscape && !inBrackets) + break; + + record16(current); + + if (lastWasEscape) { + lastWasEscape = false; + continue; + } + + switch (current) { + case '[': + inBrackets = true; + break; + case ']': + inBrackets = false; + break; + case '\\': + lastWasEscape = true; + break; + } } + pattern = makeIdentifier(m_buffer16.data(), m_buffer16.size()); + m_buffer16.resize(0); + while (isIdentPart(m_current)) { record16(m_current); shift1(); } - m_flags = UString(m_buffer16); + + flags = makeIdentifier(m_buffer16.data(), m_buffer16.size()); m_buffer16.resize(0); return true; } +bool Lexer::skipRegExp() +{ + bool lastWasEscape = false; + bool inBrackets = false; + + while (true) { + int current = m_current; + + if (isLineTerminator(current) || current == -1) + return false; + + shift1(); + + if (current == '/' && !lastWasEscape && !inBrackets) + break; + + if (lastWasEscape) { + lastWasEscape = false; + continue; + } + + switch (current) { + case '[': + inBrackets = true; + break; + case ']': + inBrackets = false; + break; + case '\\': + lastWasEscape = true; + break; + } + } + + while (isIdentPart(m_current)) + shift1(); + + return true; +} + void Lexer::clear() { - m_identifiers.clear(); + m_arena = 0; m_codeWithoutBOMs.clear(); Vector<char> newBuffer8; @@ -961,9 +1015,6 @@ void Lexer::clear() m_buffer16.swap(newBuffer16); m_isReparsing = false; - - m_pattern = UString(); - m_flags = UString(); } SourceCode Lexer::sourceCode(int openBrace, int closeBrace, int firstLine) diff --git a/JavaScriptCore/parser/Lexer.h b/JavaScriptCore/parser/Lexer.h index 2583162..c76696c 100644 --- a/JavaScriptCore/parser/Lexer.h +++ b/JavaScriptCore/parser/Lexer.h @@ -23,6 +23,7 @@ #define Lexer_h #include "Lookup.h" +#include "ParserArena.h" #include "SourceCode.h" #include <wtf/ASCIICType.h> #include <wtf/SegmentedVector.h> @@ -42,7 +43,7 @@ namespace JSC { static UChar convertUnicode(int c1, int c2, int c3, int c4); // Functions to set up parsing. - void setCode(const SourceCode&); + void setCode(const SourceCode&, ParserArena&); void setIsReparsing() { m_isReparsing = true; } // Functions for the parser itself. @@ -50,9 +51,8 @@ namespace JSC { int lineNumber() const { return m_lineNumber; } bool prevTerminator() const { return m_terminator; } SourceCode sourceCode(int openBrace, int closeBrace, int firstLine); - bool scanRegExp(); - const UString& pattern() const { return m_pattern; } - const UString& flags() const { return m_flags; } + bool scanRegExp(const Identifier*& pattern, const Identifier*& flags, UChar patternPrefix = 0); + bool skipRegExp(); // Functions for use after parsing. bool sawError() const { return m_error; } @@ -79,12 +79,11 @@ namespace JSC { int currentOffset() const; const UChar* currentCharacter() const; - JSC::Identifier* makeIdentifier(const UChar* buffer, size_t length); + const Identifier* makeIdentifier(const UChar* characters, size_t length); bool lastTokenWasRestrKeyword() const; static const size_t initialReadBufferCapacity = 32; - static const size_t initialIdentifierTableCapacity = 64; int m_lineNumber; @@ -108,13 +107,10 @@ namespace JSC { int m_next2; int m_next3; - WTF::SegmentedVector<JSC::Identifier, initialIdentifierTableCapacity> m_identifiers; + IdentifierArena* m_arena; JSGlobalData* m_globalData; - UString m_pattern; - UString m_flags; - const HashTable m_keywordTable; Vector<UChar> m_codeWithoutBOMs; @@ -140,6 +136,12 @@ namespace JSC { return (convertHex(c1, c2) << 8) | convertHex(c3, c4); } + // A bridge for yacc from the C world to the C++ world. + inline int jscyylex(void* lvalp, void* llocp, void* globalData) + { + return static_cast<JSGlobalData*>(globalData)->lexer->lex(lvalp, llocp); + } + } // namespace JSC #endif // Lexer_h diff --git a/JavaScriptCore/parser/NodeConstructors.h b/JavaScriptCore/parser/NodeConstructors.h index 780a624..dd3b981 100644 --- a/JavaScriptCore/parser/NodeConstructors.h +++ b/JavaScriptCore/parser/NodeConstructors.h @@ -27,21 +27,14 @@ namespace JSC { - inline void* ParserArenaDeletable::operator new(size_t size, JSGlobalData* globalData) + inline void* ParserArenaFreeable::operator new(size_t size, JSGlobalData* globalData) { - ParserArenaDeletable* deletable = static_cast<ParserArenaDeletable*>(fastMalloc(size)); - globalData->parser->arena().deleteWithArena(deletable); - return deletable; + return globalData->parser->arena().allocateFreeable(size); } - inline void* ParserArenaDeletable::operator new(size_t size) - { - return fastMalloc(size); - } - - inline void ParserArenaDeletable::operator delete(void* p) + inline void* ParserArenaDeletable::operator new(size_t size, JSGlobalData* globalData) { - fastFree(p); + return globalData->parser->arena().allocateDeletable(size); } inline ParserArenaRefCounted::ParserArenaRefCounted(JSGlobalData* globalData) @@ -77,19 +70,19 @@ namespace JSC { { } - inline NumberNode::NumberNode(JSGlobalData* globalData, double v) + inline NumberNode::NumberNode(JSGlobalData* globalData, double value) : ExpressionNode(globalData, ResultType::numberType()) - , m_double(v) + , m_value(value) { } - inline StringNode::StringNode(JSGlobalData* globalData, const Identifier& v) + inline StringNode::StringNode(JSGlobalData* globalData, const Identifier& value) : ExpressionNode(globalData, ResultType::stringType()) - , m_value(v) + , m_value(value) { } - inline RegExpNode::RegExpNode(JSGlobalData* globalData, const UString& pattern, const UString& flags) + inline RegExpNode::RegExpNode(JSGlobalData* globalData, const Identifier& pattern, const Identifier& flags) : ExpressionNode(globalData) , m_pattern(pattern) , m_flags(flags) @@ -154,6 +147,13 @@ namespace JSC { { } + inline PropertyNode::PropertyNode(JSGlobalData* globalData, double name, ExpressionNode* assign, Type type) + : m_name(globalData->parser->arena().identifierArena().makeNumericIdentifier(globalData, name)) + , m_assign(assign) + , m_type(type) + { + } + inline PropertyListNode::PropertyListNode(JSGlobalData* globalData, PropertyNode* node) : Node(globalData) , m_node(node) @@ -741,6 +741,7 @@ namespace JSC { inline ContinueNode::ContinueNode(JSGlobalData* globalData) : StatementNode(globalData) + , m_ident(globalData->propertyNames->nullIdentifier) { } @@ -752,6 +753,7 @@ namespace JSC { inline BreakNode::BreakNode(JSGlobalData* globalData) : StatementNode(globalData) + , m_ident(globalData->propertyNames->nullIdentifier) { } @@ -814,32 +816,22 @@ namespace JSC { inline FuncExprNode::FuncExprNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter) : ExpressionNode(globalData) - , ParserArenaRefCounted(globalData) - , m_ident(ident) , m_body(body) { - m_body->finishParsing(source, parameter); + m_body->finishParsing(source, parameter, ident); } inline FuncDeclNode::FuncDeclNode(JSGlobalData* globalData, const Identifier& ident, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter) : StatementNode(globalData) - , ParserArenaRefCounted(globalData) - , m_ident(ident) , m_body(body) { - m_body->finishParsing(source, parameter); - } - - inline CaseClauseNode::CaseClauseNode(JSGlobalData*, ExpressionNode* expr) - : m_expr(expr) - { + m_body->finishParsing(source, parameter, ident); } - inline CaseClauseNode::CaseClauseNode(JSGlobalData*, ExpressionNode* expr, SourceElements* children) + inline CaseClauseNode::CaseClauseNode(JSGlobalData*, ExpressionNode* expr, SourceElements* statements) : m_expr(expr) + , m_statements(statements) { - if (children) - children->releaseContentsIntoVector(m_children); } inline ClauseListNode::ClauseListNode(JSGlobalData*, CaseClauseNode* clause) @@ -877,15 +869,15 @@ namespace JSC { { } - inline BlockNode::BlockNode(JSGlobalData* globalData, SourceElements* children) + inline BlockNode::BlockNode(JSGlobalData* globalData, SourceElements* statements) : StatementNode(globalData) + , m_statements(statements) { - if (children) - children->releaseContentsIntoVector(m_children); } inline ForInNode::ForInNode(JSGlobalData* globalData, ExpressionNode* l, ExpressionNode* expr, StatementNode* statement) : StatementNode(globalData) + , m_ident(globalData->propertyNames->nullIdentifier) , m_init(0) , m_lexpr(l) , m_expr(expr) diff --git a/JavaScriptCore/parser/Nodes.cpp b/JavaScriptCore/parser/Nodes.cpp index 4324a06..4b97e9a 100644 --- a/JavaScriptCore/parser/Nodes.cpp +++ b/JavaScriptCore/parser/Nodes.cpp @@ -49,37 +49,6 @@ using namespace WTF; namespace JSC { -static void substitute(UString& string, const UString& substring); - -// ------------------------------ ThrowableExpressionData -------------------------------- - -static void substitute(UString& string, const UString& substring) -{ - int position = string.find("%s"); - ASSERT(position != -1); - UString newString = string.substr(0, position); - newString.append(substring); - newString.append(string.substr(position + 2)); - string = newString; -} - -RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType e, const char* msg) -{ - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), msg)); - generator.emitThrow(exception); - return exception; -} - -RegisterID* ThrowableExpressionData::emitThrowError(BytecodeGenerator& generator, ErrorType e, const char* msg, const Identifier& label) -{ - UString message = msg; - substitute(message, label.ustring()); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* exception = generator.emitNewError(generator.newTemporary(), e, jsString(generator.globalData(), message)); - generator.emitThrow(exception); - return exception; -} // ------------------------------ StatementNode -------------------------------- @@ -98,1735 +67,23 @@ void SourceElements::append(StatementNode* statement) m_statements.append(statement); } -// ------------------------------ NullNode ------------------------------------- - -RegisterID* NullNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, jsNull()); -} - -// ------------------------------ BooleanNode ---------------------------------- - -RegisterID* BooleanNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); -} - -// ------------------------------ NumberNode ----------------------------------- - -RegisterID* NumberNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_double); -} - -// ------------------------------ StringNode ----------------------------------- - -RegisterID* StringNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.emitLoad(dst, m_value); -} - -// ------------------------------ RegExpNode ----------------------------------- - -RegisterID* RegExpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - 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 == generator.ignoredResult()) - return 0; - return generator.emitNewRegExp(generator.finalDestination(dst), regExp.get()); -} - -// ------------------------------ ThisNode ------------------------------------- - -RegisterID* ThisNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - return 0; - return generator.moveToDestinationIfNeeded(dst, generator.thisRegister()); -} - -// ------------------------------ ResolveNode ---------------------------------- - -bool ResolveNode::isPure(BytecodeGenerator& generator) const -{ - return generator.isLocal(m_ident); -} - -RegisterID* ResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (dst == generator.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); -} - -// ------------------------------ ArrayNode ------------------------------------ - -RegisterID* ArrayNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - // FIXME: Should we put all of this code into emitNewArray? - - unsigned length = 0; - ElementNode* firstPutElement; - for (firstPutElement = m_element; firstPutElement; firstPutElement = firstPutElement->next()) { - if (firstPutElement->elision()) - break; - ++length; - } - - if (!firstPutElement && !m_elision) - return generator.emitNewArray(generator.finalDestination(dst), m_element); - - RefPtr<RegisterID> array = generator.emitNewArray(generator.tempDestination(dst), m_element); - - 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_elision) { - RegisterID* value = generator.emitLoad(0, jsNumber(generator.globalData(), m_elision + length)); - generator.emitPutById(array.get(), generator.propertyNames().length, value); - } - - return generator.moveToDestinationIfNeeded(dst, array.get()); -} - -bool ArrayNode::isSimpleArray() const -{ - if (m_elision || m_optional) - return false; - for (ElementNode* ptr = m_element; ptr; ptr = ptr->next()) { - if (ptr->elision()) - return false; - } - return true; -} - -ArgumentListNode* ArrayNode::toArgumentList(JSGlobalData* globalData) const -{ - ASSERT(!m_elision && !m_optional); - ElementNode* ptr = m_element; - if (!ptr) - return 0; - ArgumentListNode* head = new (globalData) ArgumentListNode(globalData, ptr->value()); - ArgumentListNode* tail = head; - ptr = ptr->next(); - for (; ptr; ptr = ptr->next()) { - ASSERT(!ptr->elision()); - tail = new (globalData) ArgumentListNode(globalData, tail, ptr->value()); - } - return head; -} - -// ------------------------------ ObjectLiteralNode ---------------------------- - -RegisterID* ObjectLiteralNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (!m_list) { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitNewObject(generator.finalDestination(dst)); - } - return generator.emitNode(dst, m_list); -} - -// ------------------------------ PropertyListNode ----------------------------- - -RegisterID* PropertyListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> newObj = generator.tempDestination(dst); - - generator.emitNewObject(newObj.get()); - - for (PropertyListNode* p = this; p; p = p->m_next) { - RegisterID* value = generator.emitNode(p->m_node->m_assign); - - switch (p->m_node->m_type) { - case PropertyNode::Constant: { - generator.emitPutById(newObj.get(), p->m_node->name(), value); - break; - } - case PropertyNode::Getter: { - generator.emitPutGetter(newObj.get(), p->m_node->name(), value); - break; - } - case PropertyNode::Setter: { - generator.emitPutSetter(newObj.get(), p->m_node->name(), value); - break; - } - default: - ASSERT_NOT_REACHED(); - } - } - - return generator.moveToDestinationIfNeeded(dst, newObj.get()); -} - -// ------------------------------ BracketAccessorNode -------------------------------- - -RegisterID* BracketAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments, m_subscript->isPure(generator)); - RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitGetByVal(generator.finalDestination(dst), base.get(), property); -} - -// ------------------------------ DotAccessorNode -------------------------------- - -RegisterID* DotAccessorNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RegisterID* base = generator.emitNode(m_base); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitGetById(generator.finalDestination(dst), base, m_ident); -} - -// ------------------------------ ArgumentListNode ----------------------------- - -RegisterID* ArgumentListNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - ASSERT(m_expr); - return generator.emitNode(dst, m_expr); -} - -// ------------------------------ NewExprNode ---------------------------------- - -RegisterID* NewExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> func = generator.emitNode(m_expr); - return generator.emitConstruct(generator.finalDestination(dst), func.get(), m_args, divot(), startOffset(), endOffset()); -} - -// ------------------------------ EvalFunctionCallNode ---------------------------------- - -RegisterID* EvalFunctionCallNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> func = generator.tempDestination(dst); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - generator.emitExpressionInfo(divot() - startOffset() + 4, 4, 0); - generator.emitResolveWithBase(thisRegister.get(), func.get(), generator.propertyNames().eval); - return generator.emitCallEval(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); -} - -// ------------------------------ FunctionCallValueNode ---------------------------------- - -RegisterID* FunctionCallValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> func = generator.emitNode(m_expr); - RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); - return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); -} - -// ------------------------------ FunctionCallResolveNode ---------------------------------- - -RegisterID* FunctionCallResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RefPtr<RegisterID> local = generator.registerFor(m_ident)) { - RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); - return generator.emitCall(generator.finalDestination(dst, thisRegister.get()), local.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - } - - 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); - RefPtr<RegisterID> thisRegister = generator.emitLoad(generator.newTemporary(), jsNull()); - return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - } - - RefPtr<RegisterID> func = generator.newTemporary(); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - int identifierStart = divot() - startOffset(); - generator.emitExpressionInfo(identifierStart + m_ident.size(), m_ident.size(), 0); - generator.emitResolveWithBase(thisRegister.get(), func.get(), m_ident); - return generator.emitCall(generator.finalDestination(dst, func.get()), func.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); -} - -// ------------------------------ FunctionCallBracketNode ---------------------------------- - -RegisterID* FunctionCallBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - RegisterID* property = generator.emitNode(m_subscript); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> function = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property); - RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); - return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); -} - -// ------------------------------ FunctionCallDotNode ---------------------------------- - -RegisterID* FunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) +inline StatementNode* SourceElements::singleStatement() const { - RefPtr<RegisterID> function = generator.tempDestination(dst); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - generator.emitNode(thisRegister.get(), m_base); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - generator.emitMethodCheck(); - generator.emitGetById(function.get(), thisRegister.get(), m_ident); - return generator.emitCall(generator.finalDestination(dst, function.get()), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); -} - -RegisterID* CallFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<Label> realCall = generator.newLabel(); - RefPtr<Label> end = generator.newLabel(); - RefPtr<RegisterID> base = generator.emitNode(m_base); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); - RefPtr<RegisterID> finalDestination = generator.finalDestination(dst, function.get()); - generator.emitJumpIfNotFunctionCall(function.get(), realCall.get()); - { - RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - ArgumentListNode* oldList = m_args->m_listNode; - if (m_args->m_listNode && m_args->m_listNode->m_expr) { - generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); - m_args->m_listNode = m_args->m_listNode->m_next; - } else - generator.emitLoad(thisRegister.get(), jsNull()); - - generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - generator.emitJump(end.get()); - m_args->m_listNode = oldList; - } - generator.emitLabel(realCall.get()); - { - RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); - generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - } - generator.emitLabel(end.get()); - return finalDestination.get(); -} - -static bool areTrivialApplyArguments(ArgumentsNode* args) -{ - return !args->m_listNode || !args->m_listNode->m_expr || !args->m_listNode->m_next - || (!args->m_listNode->m_next->m_next && args->m_listNode->m_next->m_expr->isSimpleArray()); -} - -RegisterID* ApplyFunctionCallDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - // A few simple cases can be trivially handled as ordinary function calls. - // function.apply(), function.apply(arg) -> identical to function.call - // function.apply(thisArg, [arg0, arg1, ...]) -> can be trivially coerced into function.call(thisArg, arg0, arg1, ...) and saves object allocation - bool mayBeCall = areTrivialApplyArguments(m_args); - - RefPtr<Label> realCall = generator.newLabel(); - RefPtr<Label> end = generator.newLabel(); - RefPtr<RegisterID> base = generator.emitNode(m_base); - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> function = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); - RefPtr<RegisterID> finalDestination = generator.finalDestination(dst, function.get()); - generator.emitJumpIfNotFunctionApply(function.get(), realCall.get()); - { - if (mayBeCall) { - RefPtr<RegisterID> realFunction = generator.emitMove(generator.tempDestination(dst), base.get()); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - ArgumentListNode* oldList = m_args->m_listNode; - if (m_args->m_listNode && m_args->m_listNode->m_expr) { - generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); - m_args->m_listNode = m_args->m_listNode->m_next; - if (m_args->m_listNode) { - ASSERT(m_args->m_listNode->m_expr->isSimpleArray()); - ASSERT(!m_args->m_listNode->m_next); - m_args->m_listNode = static_cast<ArrayNode*>(m_args->m_listNode->m_expr)->toArgumentList(generator.globalData()); - } - } else - generator.emitLoad(thisRegister.get(), jsNull()); - generator.emitCall(finalDestination.get(), realFunction.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - m_args->m_listNode = oldList; - } else { - ASSERT(m_args->m_listNode && m_args->m_listNode->m_next); - RefPtr<RegisterID> realFunction = generator.emitMove(generator.newTemporary(), base.get()); - RefPtr<RegisterID> argsCountRegister = generator.newTemporary(); - RefPtr<RegisterID> thisRegister = generator.newTemporary(); - RefPtr<RegisterID> argsRegister = generator.newTemporary(); - generator.emitNode(thisRegister.get(), m_args->m_listNode->m_expr); - ArgumentListNode* args = m_args->m_listNode->m_next; - bool isArgumentsApply = false; - if (args->m_expr->isResolveNode()) { - ResolveNode* resolveNode = static_cast<ResolveNode*>(args->m_expr); - isArgumentsApply = generator.willResolveToArguments(resolveNode->identifier()); - if (isArgumentsApply) - generator.emitMove(argsRegister.get(), generator.uncheckedRegisterForArguments()); - } - if (!isArgumentsApply) - generator.emitNode(argsRegister.get(), args->m_expr); - while ((args = args->m_next)) - generator.emitNode(args->m_expr); - - generator.emitLoadVarargs(argsCountRegister.get(), argsRegister.get()); - generator.emitCallVarargs(finalDestination.get(), realFunction.get(), thisRegister.get(), argsCountRegister.get(), divot(), startOffset(), endOffset()); - } - generator.emitJump(end.get()); - } - generator.emitLabel(realCall.get()); - { - RefPtr<RegisterID> thisRegister = generator.emitMove(generator.newTemporary(), base.get()); - generator.emitCall(finalDestination.get(), function.get(), thisRegister.get(), m_args, divot(), startOffset(), endOffset()); - } - generator.emitLabel(end.get()); - return finalDestination.get(); -} - -// ------------------------------ PostfixResolveNode ---------------------------------- - -static RegisterID* emitPreIncOrDec(BytecodeGenerator& generator, RegisterID* srcDst, Operator oper) -{ - return (oper == OpPlusPlus) ? generator.emitPreInc(srcDst) : generator.emitPreDec(srcDst); -} - -static RegisterID* emitPostIncOrDec(BytecodeGenerator& generator, RegisterID* dst, RegisterID* srcDst, Operator oper) -{ - if (srcDst == dst) - return generator.emitToJSNumber(dst, srcDst); - return (oper == OpPlusPlus) ? generator.emitPostInc(dst, srcDst) : generator.emitPostDec(dst, srcDst); -} - -RegisterID* PostfixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitToJSNumber(generator.finalDestination(dst), local); - } - - if (dst == generator.ignoredResult()) - return emitPreIncOrDec(generator, local, m_operator); - return emitPostIncOrDec(generator, generator.finalDestination(dst), local, m_operator); - } - - 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 == generator.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; - } - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RefPtr<RegisterID> value = generator.newTemporary(); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), value.get(), m_ident); - RegisterID* oldValue; - if (dst == generator.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 ---------------------------------- - -RegisterID* PostfixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - RefPtr<RegisterID> property = generator.emitNode(m_subscript); - - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetByVal(generator.newTemporary(), base.get(), property.get()); - RegisterID* oldValue; - if (dst == generator.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(divot(), startOffset(), endOffset()); - generator.emitPutByVal(base.get(), property.get(), value.get()); - return oldValue; -} - -// ------------------------------ PostfixDotNode ---------------------------------- - -RegisterID* PostfixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetById(generator.newTemporary(), base.get(), m_ident); - RegisterID* oldValue; - if (dst == generator.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(divot(), startOffset(), endOffset()); - generator.emitPutById(base.get(), m_ident, value.get()); - return oldValue; -} - -// ------------------------------ PostfixErrorNode ----------------------------------- - -RegisterID* PostfixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - 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 ----------------------------------- - -RegisterID* DeleteResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (generator.registerFor(m_ident)) - return generator.emitLoad(generator.finalDestination(dst), false); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - RegisterID* base = generator.emitResolveBase(generator.tempDestination(dst), m_ident); - return generator.emitDeleteById(generator.finalDestination(dst, base), base, m_ident); -} - -// ------------------------------ DeleteBracketNode ----------------------------------- - -RegisterID* DeleteBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> r0 = generator.emitNode(m_base); - RegisterID* r1 = generator.emitNode(m_subscript); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitDeleteByVal(generator.finalDestination(dst), r0.get(), r1); -} - -// ------------------------------ DeleteDotNode ----------------------------------- - -RegisterID* DeleteDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RegisterID* r0 = generator.emitNode(m_base); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitDeleteById(generator.finalDestination(dst), r0, m_ident); -} - -// ------------------------------ DeleteValueNode ----------------------------------- - -RegisterID* DeleteValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitNode(generator.ignoredResult(), m_expr); - - // delete on a non-location expression ignores the value and returns true - return generator.emitLoad(generator.finalDestination(dst), true); -} - -// ------------------------------ VoidNode ------------------------------------- - -RegisterID* VoidNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) { - generator.emitNode(generator.ignoredResult(), m_expr); - return 0; - } - RefPtr<RegisterID> r0 = generator.emitNode(m_expr); - return generator.emitLoad(dst, jsUndefined()); -} - -// ------------------------------ TypeOfValueNode ----------------------------------- - -RegisterID* TypeOfResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (dst == generator.ignoredResult()) - return 0; - return generator.emitTypeOf(generator.finalDestination(dst), local); - } - - RefPtr<RegisterID> scratch = generator.emitResolveBase(generator.tempDestination(dst), m_ident); - generator.emitGetById(scratch.get(), scratch.get(), m_ident); - if (dst == generator.ignoredResult()) - return 0; - return generator.emitTypeOf(generator.finalDestination(dst, scratch.get()), scratch.get()); -} - -// ------------------------------ TypeOfValueNode ----------------------------------- - -RegisterID* TypeOfValueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) { - generator.emitNode(generator.ignoredResult(), m_expr); - return 0; - } - RefPtr<RegisterID> src = generator.emitNode(m_expr); - return generator.emitTypeOf(generator.finalDestination(dst), src.get()); -} - -// ------------------------------ PrefixResolveNode ---------------------------------- - -RegisterID* PrefixResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { - if (dst == generator.ignoredResult()) - return 0; - RefPtr<RegisterID> r0 = generator.emitLoad(generator.finalDestination(dst), (m_operator == OpPlusPlus) ? 1.0 : -1.0); - return generator.emitBinaryOp(op_add, r0.get(), local, r0.get(), OperandTypes()); - } - - emitPreIncOrDec(generator, local, m_operator); - return generator.moveToDestinationIfNeeded(dst, local); - } - - 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()); - } - - generator.emitExpressionInfo(divot(), startOffset(), 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 ---------------------------------- - -RegisterID* PrefixBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - RefPtr<RegisterID> property = generator.emitNode(m_subscript); - RefPtr<RegisterID> propDst = generator.tempDestination(dst); - - generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, 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(divot(), startOffset(), endOffset()); - generator.emitPutByVal(base.get(), property.get(), value); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); -} - -// ------------------------------ PrefixDotNode ---------------------------------- - -RegisterID* PrefixDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNode(m_base); - RefPtr<RegisterID> propDst = generator.tempDestination(dst); - - generator.emitExpressionInfo(divot() + m_subexpressionDivotOffset, m_subexpressionStartOffset, 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(divot(), startOffset(), endOffset()); - generator.emitPutById(base.get(), m_ident, value); - return generator.moveToDestinationIfNeeded(dst, propDst.get()); -} - -// ------------------------------ PrefixErrorNode ----------------------------------- - -RegisterID* PrefixErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - 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."); -} - -// ------------------------------ Unary Operation Nodes ----------------------------------- - -RegisterID* UnaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RegisterID* src = generator.emitNode(m_expr); - return generator.emitUnaryOp(opcodeID(), generator.finalDestination(dst), src); -} - -// ------------------------------ Binary Operation Nodes ----------------------------------- - -// BinaryOpNode::emitStrcat: -// -// This node generates an op_strcat operation. This opcode can handle concatenation of three or -// more values, where we can determine a set of separate op_add operations would be operating on -// string values. -// -// This function expects to be operating on a graph of AST nodes looking something like this: -// -// (a)... (b) -// \ / -// (+) (c) -// \ / -// [d] ((+)) -// \ / -// [+=] -// -// The assignment operation is optional, if it exists the register holding the value on the -// lefthand side of the assignment should be passing as the optional 'lhs' argument. -// -// The method should be called on the node at the root of the tree of regular binary add -// operations (marked in the diagram with a double set of parentheses). This node must -// be performing a string concatenation (determined by statically detecting that at least -// one child must be a string). -// -// Since the minimum number of values being concatenated together is expected to be 3, if -// a lhs to a concatenating assignment is not provided then the root add should have at -// least one left child that is also an add that can be determined to be operating on strings. -// -RegisterID* BinaryOpNode::emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs, ReadModifyResolveNode* emitExpressionInfoForMe) -{ - ASSERT(isAdd()); - ASSERT(resultDescriptor().definitelyIsString()); - - // Create a list of expressions for all the adds in the tree of nodes we can convert into - // a string concatenation. The rightmost node (c) is added first. The rightmost node is - // added first, and the leftmost child is never added, so the vector produced for the - // example above will be [ c, b ]. - Vector<ExpressionNode*, 16> reverseExpressionList; - reverseExpressionList.append(m_expr2); - - // Examine the left child of the add. So long as this is a string add, add its right-child - // to the list, and keep processing along the left fork. - ExpressionNode* leftMostAddChild = m_expr1; - while (leftMostAddChild->isAdd() && leftMostAddChild->resultDescriptor().definitelyIsString()) { - reverseExpressionList.append(static_cast<AddNode*>(leftMostAddChild)->m_expr2); - leftMostAddChild = static_cast<AddNode*>(leftMostAddChild)->m_expr1; - } - - Vector<RefPtr<RegisterID>, 16> temporaryRegisters; - - // If there is an assignment, allocate a temporary to hold the lhs after conversion. - // We could possibly avoid this (the lhs is converted last anyway, we could let the - // op_strcat node handle its conversion if required). - if (lhs) - temporaryRegisters.append(generator.newTemporary()); - - // Emit code for the leftmost node ((a) in the example). - temporaryRegisters.append(generator.newTemporary()); - RegisterID* leftMostAddChildTempRegister = temporaryRegisters.last().get(); - generator.emitNode(leftMostAddChildTempRegister, leftMostAddChild); - - // Note on ordering of conversions: - // - // We maintain the same ordering of conversions as we would see if the concatenations - // was performed as a sequence of adds (otherwise this optimization could change - // behaviour should an object have been provided a valueOf or toString method). - // - // Considering the above example, the sequnce of execution is: - // * evaluate operand (a) - // * evaluate operand (b) - // * convert (a) to primitive <- (this would be triggered by the first add) - // * convert (b) to primitive <- (ditto) - // * evaluate operand (c) - // * convert (c) to primitive <- (this would be triggered by the second add) - // And optionally, if there is an assignment: - // * convert (d) to primitive <- (this would be triggered by the assigning addition) - // - // As such we do not plant an op to convert the leftmost child now. Instead, use - // 'leftMostAddChildTempRegister' as a flag to trigger generation of the conversion - // once the second node has been generated. However, if the leftmost child is an - // immediate we can trivially determine that no conversion will be required. - // If this is the case - if (leftMostAddChild->isString()) - leftMostAddChildTempRegister = 0; - - while (reverseExpressionList.size()) { - ExpressionNode* node = reverseExpressionList.last(); - reverseExpressionList.removeLast(); - - // Emit the code for the current node. - temporaryRegisters.append(generator.newTemporary()); - generator.emitNode(temporaryRegisters.last().get(), node); - - // On the first iteration of this loop, when we first reach this point we have just - // generated the second node, which means it is time to convert the leftmost operand. - if (leftMostAddChildTempRegister) { - generator.emitToPrimitive(leftMostAddChildTempRegister, leftMostAddChildTempRegister); - leftMostAddChildTempRegister = 0; // Only do this once. - } - // Plant a conversion for this node, if necessary. - if (!node->isString()) - generator.emitToPrimitive(temporaryRegisters.last().get(), temporaryRegisters.last().get()); - } - ASSERT(temporaryRegisters.size() >= 3); - - // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. - // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. - if (emitExpressionInfoForMe) - generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); - - // If there is an assignment convert the lhs now. This will also copy lhs to - // the temporary register we allocated for it. - if (lhs) - generator.emitToPrimitive(temporaryRegisters[0].get(), lhs); - - return generator.emitStrcat(generator.finalDestination(dst, temporaryRegisters[0].get()), temporaryRegisters[0].get(), temporaryRegisters.size()); -} - -RegisterID* BinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - OpcodeID opcodeID = this->opcodeID(); - - if (opcodeID == op_add && m_expr1->isAdd() && m_expr1->resultDescriptor().definitelyIsString()) - return emitStrcat(generator, dst); - - if (opcodeID == op_neq) { - if (m_expr1->isNull() || m_expr2->isNull()) { - RefPtr<RegisterID> src = generator.tempDestination(dst); - generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); - return generator.emitUnaryOp(op_neq_null, generator.finalDestination(dst, src.get()), src.get()); - } - } - - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); - return generator.emitBinaryOp(opcodeID, generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); -} - -RegisterID* EqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (m_expr1->isNull() || m_expr2->isNull()) { - RefPtr<RegisterID> src = generator.tempDestination(dst); - generator.emitNode(src.get(), m_expr1->isNull() ? m_expr2 : m_expr1); - return generator.emitUnaryOp(op_eq_null, generator.finalDestination(dst, src.get()), src.get()); - } - - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); - return generator.emitEqualityOp(op_eq, generator.finalDestination(dst, src1.get()), src1.get(), src2); -} - -RegisterID* StrictEqualNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); - return generator.emitEqualityOp(op_stricteq, generator.finalDestination(dst, src1.get()), src1.get(), src2); -} - -RegisterID* ReverseBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); - return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src2, src1.get(), OperandTypes(m_expr2->resultDescriptor(), m_expr1->resultDescriptor())); -} - -RegisterID* ThrowableBinaryOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RegisterID* src2 = generator.emitNode(m_expr2); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitBinaryOp(opcodeID(), generator.finalDestination(dst, src1.get()), src1.get(), src2, OperandTypes(m_expr1->resultDescriptor(), m_expr2->resultDescriptor())); -} - -RegisterID* InstanceOfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> src1 = generator.emitNodeForLeftHandSide(m_expr1, m_rightHasAssignments, m_expr2->isPure(generator)); - RefPtr<RegisterID> src2 = generator.emitNode(m_expr2); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitGetByIdExceptionInfo(op_instanceof); - RegisterID* src2Prototype = generator.emitGetById(generator.newTemporary(), src2.get(), generator.globalData()->propertyNames->prototype); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitInstanceOf(generator.finalDestination(dst, src1.get()), src1.get(), src2.get(), src2Prototype); -} - -// ------------------------------ LogicalOpNode ---------------------------- - -RegisterID* LogicalOpNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> temp = generator.tempDestination(dst); - RefPtr<Label> target = generator.newLabel(); - - generator.emitNode(temp.get(), m_expr1); - if (m_operator == OpLogicalAnd) - generator.emitJumpIfFalse(temp.get(), target.get()); - else - generator.emitJumpIfTrue(temp.get(), target.get()); - generator.emitNode(temp.get(), m_expr2); - generator.emitLabel(target.get()); - - return generator.moveToDestinationIfNeeded(dst, temp.get()); -} - -// ------------------------------ ConditionalNode ------------------------------ - -RegisterID* ConditionalNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> newDst = generator.finalDestination(dst); - RefPtr<Label> beforeElse = generator.newLabel(); - RefPtr<Label> afterElse = generator.newLabel(); - - RegisterID* cond = generator.emitNode(m_logical); - generator.emitJumpIfFalse(cond, beforeElse.get()); - - generator.emitNode(newDst.get(), m_expr1); - generator.emitJump(afterElse.get()); - - generator.emitLabel(beforeElse.get()); - generator.emitNode(newDst.get(), m_expr2); - - generator.emitLabel(afterElse.get()); - - return newDst.get(); -} - -// ------------------------------ ReadModifyResolveNode ----------------------------------- - -// FIXME: should this be moved to be a method on BytecodeGenerator? -static ALWAYS_INLINE RegisterID* emitReadModifyAssignment(BytecodeGenerator& generator, RegisterID* dst, RegisterID* src1, ExpressionNode* m_right, Operator oper, OperandTypes types, ReadModifyResolveNode* emitExpressionInfoForMe = 0) -{ - OpcodeID opcodeID; - switch (oper) { - case OpMultEq: - opcodeID = op_mul; - break; - case OpDivEq: - opcodeID = op_div; - break; - case OpPlusEq: - if (m_right->isAdd() && m_right->resultDescriptor().definitelyIsString()) - return static_cast<AddNode*>(m_right)->emitStrcat(generator, dst, src1, emitExpressionInfoForMe); - opcodeID = op_add; - break; - case OpMinusEq: - opcodeID = op_sub; - break; - case OpLShift: - opcodeID = op_lshift; - break; - case OpRShift: - opcodeID = op_rshift; - break; - case OpURShift: - opcodeID = op_urshift; - break; - case OpAndEq: - opcodeID = op_bitand; - break; - case OpXOrEq: - opcodeID = op_bitxor; - break; - case OpOrEq: - opcodeID = op_bitor; - break; - case OpModEq: - opcodeID = op_mod; - break; - default: - ASSERT_NOT_REACHED(); - return dst; - } - - RegisterID* src2 = generator.emitNode(m_right); - - // Certain read-modify nodes require expression info to be emitted *after* m_right has been generated. - // If this is required the node is passed as 'emitExpressionInfoForMe'; do so now. - if (emitExpressionInfoForMe) - generator.emitExpressionInfo(emitExpressionInfoForMe->divot(), emitExpressionInfoForMe->startOffset(), emitExpressionInfoForMe->endOffset()); - - return generator.emitBinaryOp(opcodeID, dst, src1, src2, types); -} - -RegisterID* ReadModifyResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) { - return emitReadModifyAssignment(generator, generator.finalDestination(dst), local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - } - - if (generator.leftHandSideNeedsCopy(m_rightHasAssignments, m_right->isPure(generator))) { - RefPtr<RegisterID> result = generator.newTemporary(); - generator.emitMove(result.get(), local); - emitReadModifyAssignment(generator, result.get(), result.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitMove(local, result.get()); - return generator.moveToDestinationIfNeeded(dst, result.get()); - } - - RegisterID* result = emitReadModifyAssignment(generator, local, local, m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - return generator.moveToDestinationIfNeeded(dst, result); - } - - 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* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - generator.emitPutScopedVar(depth, index, result, globalObject); - return result; - } - - RefPtr<RegisterID> src1 = generator.tempDestination(dst); - generator.emitExpressionInfo(divot() - startOffset() + m_ident.size(), m_ident.size(), 0); - RefPtr<RegisterID> base = generator.emitResolveWithBase(generator.newTemporary(), src1.get(), m_ident); - RegisterID* result = emitReadModifyAssignment(generator, generator.finalDestination(dst, src1.get()), src1.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor()), this); - return generator.emitPutById(base.get(), m_ident, result); -} - -// ------------------------------ AssignResolveNode ----------------------------------- - -RegisterID* AssignResolveNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (RegisterID* local = generator.registerFor(m_ident)) { - if (generator.isLocalConstant(m_ident)) - return generator.emitNode(dst, m_right); - - RegisterID* result = generator.emitNode(local, m_right); - return generator.moveToDestinationIfNeeded(dst, result); - } - - int index = 0; - size_t depth = 0; - JSObject* globalObject = 0; - if (generator.findScopedProperty(m_ident, index, depth, true, globalObject) && index != missingSymbolMarker()) { - if (dst == generator.ignoredResult()) - dst = 0; - RegisterID* value = generator.emitNode(dst, m_right); - generator.emitPutScopedVar(depth, index, value, globalObject); - return value; - } - - RefPtr<RegisterID> base = generator.emitResolveBase(generator.newTemporary(), m_ident); - if (dst == generator.ignoredResult()) - dst = 0; - RegisterID* value = generator.emitNode(dst, m_right); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitPutById(base.get(), m_ident, value); -} - -// ------------------------------ AssignDotNode ----------------------------------- - -RegisterID* AssignDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); - RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); - RegisterID* result = generator.emitNode(value.get(), m_right); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutById(base.get(), m_ident, result); - return generator.moveToDestinationIfNeeded(dst, result); -} - -// ------------------------------ ReadModifyDotNode ----------------------------------- - -RegisterID* ReadModifyDotNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_rightHasAssignments, m_right->isPure(generator)); - - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetById(generator.tempDestination(dst), base.get(), m_ident); - RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - return generator.emitPutById(base.get(), m_ident, updatedValue); -} - -// ------------------------------ AssignErrorNode ----------------------------------- - -RegisterID* AssignErrorNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - return emitThrowError(generator, ReferenceError, "Left side of assignment is not a reference."); -} - -// ------------------------------ AssignBracketNode ----------------------------------- - -RegisterID* AssignBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); - RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); - RefPtr<RegisterID> value = generator.destinationForAssignResult(dst); - RegisterID* result = generator.emitNode(value.get(), m_right); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutByVal(base.get(), property.get(), result); - return generator.moveToDestinationIfNeeded(dst, result); -} - -// ------------------------------ ReadModifyBracketNode ----------------------------------- - -RegisterID* ReadModifyBracketNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<RegisterID> base = generator.emitNodeForLeftHandSide(m_base, m_subscriptHasAssignments || m_rightHasAssignments, m_subscript->isPure(generator) && m_right->isPure(generator)); - RefPtr<RegisterID> property = generator.emitNodeForLeftHandSide(m_subscript, m_rightHasAssignments, m_right->isPure(generator)); - - generator.emitExpressionInfo(divot() - m_subexpressionDivotOffset, startOffset() - m_subexpressionDivotOffset, m_subexpressionEndOffset); - RefPtr<RegisterID> value = generator.emitGetByVal(generator.tempDestination(dst), base.get(), property.get()); - RegisterID* updatedValue = emitReadModifyAssignment(generator, generator.finalDestination(dst, value.get()), value.get(), m_right, m_operator, OperandTypes(ResultType::unknownType(), m_right->resultDescriptor())); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutByVal(base.get(), property.get(), updatedValue); - - return updatedValue; -} - -// ------------------------------ CommaNode ------------------------------------ - -RegisterID* CommaNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - ASSERT(m_expressions.size() > 1); - for (size_t i = 0; i < m_expressions.size() - 1; i++) - generator.emitNode(generator.ignoredResult(), m_expressions[i]); - return generator.emitNode(dst, m_expressions.last()); -} - -// ------------------------------ ConstDeclNode ------------------------------------ - -RegisterID* ConstDeclNode::emitCodeSingle(BytecodeGenerator& generator) -{ - if (RegisterID* local = generator.constRegisterFor(m_ident)) { - if (!m_init) - return local; - - return generator.emitNode(local, m_init); - } - - // 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) : generator.emitLoad(0, jsUndefined()); - return generator.emitPutById(base.get(), m_ident, value); -} - -RegisterID* ConstDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - RegisterID* result = 0; - for (ConstDeclNode* n = this; n; n = n->m_next) - result = n->emitCodeSingle(generator); - - return result; -} - -// ------------------------------ ConstStatementNode ----------------------------- - -RegisterID* ConstStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - return generator.emitNode(m_next); -} - -// ------------------------------ Helper functions for handling Vectors of StatementNode ------------------------------- - -static inline void statementListEmitCode(const StatementVector& statements, BytecodeGenerator& generator, RegisterID* dst) -{ - size_t size = statements.size(); - for (size_t i = 0; i < size; ++i) - generator.emitNode(dst, statements[i]); -} - -// ------------------------------ BlockNode ------------------------------------ - -RegisterID* BlockNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - statementListEmitCode(m_children, generator, dst); - return 0; -} - -// ------------------------------ EmptyStatementNode --------------------------- - -RegisterID* EmptyStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - return dst; -} - -// ------------------------------ DebuggerStatementNode --------------------------- - -RegisterID* DebuggerStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(DidReachBreakpoint, firstLine(), lastLine()); - return dst; -} - -// ------------------------------ ExprStatementNode ---------------------------- - -RegisterID* ExprStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - ASSERT(m_expr); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - return generator.emitNode(dst, m_expr); -} - -// ------------------------------ VarStatementNode ---------------------------- - -RegisterID* VarStatementNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - ASSERT(m_expr); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - return generator.emitNode(m_expr); -} - -// ------------------------------ IfNode --------------------------------------- - -RegisterID* IfNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<Label> afterThen = generator.newLabel(); - - RegisterID* cond = generator.emitNode(m_condition); - generator.emitJumpIfFalse(cond, afterThen.get()); - - generator.emitNode(dst, m_ifBlock); - generator.emitLabel(afterThen.get()); - - // FIXME: This should return the last statement executed so that it can be returned as a Completion. - return 0; -} - -// ------------------------------ IfElseNode --------------------------------------- - -RegisterID* IfElseNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<Label> beforeElse = generator.newLabel(); - RefPtr<Label> afterElse = generator.newLabel(); - - RegisterID* cond = generator.emitNode(m_condition); - generator.emitJumpIfFalse(cond, beforeElse.get()); - - generator.emitNode(dst, m_ifBlock); - generator.emitJump(afterElse.get()); - - generator.emitLabel(beforeElse.get()); - - generator.emitNode(dst, m_elseBlock); - - generator.emitLabel(afterElse.get()); - - // FIXME: This should return the last statement executed so that it can be returned as a Completion. - return 0; -} - -// ------------------------------ DoWhileNode ---------------------------------- - -RegisterID* DoWhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - RefPtr<Label> topOfLoop = generator.newLabel(); - generator.emitLabel(topOfLoop.get()); - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); - - generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); - RegisterID* cond = generator.emitNode(m_expr); - generator.emitJumpIfTrue(cond, topOfLoop.get()); - - generator.emitLabel(scope->breakTarget()); - return result.get(); -} - -// ------------------------------ WhileNode ------------------------------------ - -RegisterID* WhileNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - generator.emitJump(scope->continueTarget()); - - RefPtr<Label> topOfLoop = generator.newLabel(); - generator.emitLabel(topOfLoop.get()); - - generator.emitNode(dst, m_statement); - - generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, m_expr->lineNo(), m_expr->lineNo()); - RegisterID* cond = generator.emitNode(m_expr); - generator.emitJumpIfTrue(cond, topOfLoop.get()); - - generator.emitLabel(scope->breakTarget()); - - // FIXME: This should return the last statement executed so that it can be returned as a Completion - return 0; -} - -// ------------------------------ ForNode -------------------------------------- - -RegisterID* ForNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (m_expr1) - generator.emitNode(generator.ignoredResult(), m_expr1); - - RefPtr<Label> condition = generator.newLabel(); - generator.emitJump(condition.get()); - - RefPtr<Label> topOfLoop = generator.newLabel(); - generator.emitLabel(topOfLoop.get()); - - RefPtr<RegisterID> result = generator.emitNode(dst, m_statement); - - generator.emitLabel(scope->continueTarget()); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - if (m_expr3) - generator.emitNode(generator.ignoredResult(), m_expr3); - - generator.emitLabel(condition.get()); - if (m_expr2) { - RegisterID* cond = generator.emitNode(m_expr2); - generator.emitJumpIfTrue(cond, topOfLoop.get()); - } else - generator.emitJump(topOfLoop.get()); - - generator.emitLabel(scope->breakTarget()); - return result.get(); -} - -// ------------------------------ ForInNode ------------------------------------ - -RegisterID* ForInNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Loop); - - if (!m_lexpr->isLocation()) - return emitThrowError(generator, ReferenceError, "Left side of for-in statement is not a reference."); - - RefPtr<Label> continueTarget = generator.newLabel(); - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (m_init) - generator.emitNode(generator.ignoredResult(), m_init); - RegisterID* forInBase = generator.emitNode(m_expr); - RefPtr<RegisterID> iter = generator.emitGetPropertyNames(generator.newTemporary(), forInBase); - generator.emitJump(scope->continueTarget()); - - RefPtr<Label> loopStart = generator.newLabel(); - generator.emitLabel(loopStart.get()); - - RegisterID* propertyName; - if (m_lexpr->isResolveNode()) { - const Identifier& ident = static_cast<ResolveNode*>(m_lexpr)->identifier(); - propertyName = generator.registerFor(ident); - if (!propertyName) { - propertyName = generator.newTemporary(); - RefPtr<RegisterID> protect = propertyName; - RegisterID* base = generator.emitResolveBase(generator.newTemporary(), ident); - - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitPutById(base, ident, propertyName); - } - } else if (m_lexpr->isDotAccessorNode()) { - DotAccessorNode* assignNode = static_cast<DotAccessorNode*>(m_lexpr); - 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); - 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); - } - - generator.emitNode(dst, m_statement); - - generator.emitLabel(scope->continueTarget()); - generator.emitNextPropertyName(propertyName, iter.get(), loopStart.get()); - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - generator.emitLabel(scope->breakTarget()); - return dst; -} - -// ------------------------------ ContinueNode --------------------------------- - -// ECMA 12.7 -RegisterID* ContinueNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - 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 -RegisterID* BreakNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - 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 ----------------------------------- - -RegisterID* ReturnNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - if (generator.codeType() != FunctionCode) - return emitThrowError(generator, SyntaxError, "Invalid return statement."); - - if (dst == generator.ignoredResult()) - dst = 0; - RegisterID* r0 = m_value ? generator.emitNode(dst, m_value) : generator.emitLoad(dst, jsUndefined()); - RefPtr<RegisterID> returnRegister; - if (generator.scopeDepth()) { - RefPtr<Label> l0 = generator.newLabel(); - if (generator.hasFinaliser() && !r0->isTemporary()) { - returnRegister = generator.emitMove(generator.newTemporary(), r0); - r0 = returnRegister.get(); - } - generator.emitJumpScopes(l0.get(), 0); - generator.emitLabel(l0.get()); - } - generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); - return generator.emitReturn(r0); -} - -// ------------------------------ WithNode ------------------------------------- - -RegisterID* WithNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<RegisterID> scope = generator.newTemporary(); - generator.emitNode(scope.get(), m_expr); // scope must be protected until popped - generator.emitExpressionInfo(m_divot, m_expressionLength, 0); - generator.emitPushScope(scope.get()); - RegisterID* result = generator.emitNode(dst, m_statement); - generator.emitPopScope(); - return result; -} - -// ------------------------------ CaseBlockNode -------------------------------- - -enum SwitchKind { - SwitchUnset = 0, - SwitchNumber = 1, - SwitchString = 2, - SwitchNeither = 3 -}; - -static void processClauseList(ClauseListNode* list, Vector<ExpressionNode*, 8>& literalVector, SwitchKind& typeForTable, bool& singleCharacterSwitch, int32_t& min_num, int32_t& max_num) -{ - for (; list; list = list->getNext()) { - ExpressionNode* clauseExpression = list->getClause()->expr(); - literalVector.append(clauseExpression); - if (clauseExpression->isNumber()) { - double value = static_cast<NumberNode*>(clauseExpression)->value(); - int32_t intVal = static_cast<int32_t>(value); - if ((typeForTable & ~SwitchNumber) || (intVal != value)) { - typeForTable = SwitchNeither; - break; - } - 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; - } -} - -SwitchInfo::SwitchType CaseBlockNode::tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num) -{ - SwitchKind typeForTable = SwitchUnset; - bool singleCharacterSwitch = true; - - processClauseList(m_list1, literalVector, typeForTable, singleCharacterSwitch, min_num, max_num); - processClauseList(m_list2, 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; - } - - return SwitchInfo::SwitchString; -} - -RegisterID* CaseBlockNode::emitBytecodeForBlock(BytecodeGenerator& generator, RegisterID* switchExpression, RegisterID* dst) -{ - RefPtr<Label> defaultLabel; - Vector<RefPtr<Label>, 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); - - 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; 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; 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()); - } - - RegisterID* result = 0; - - size_t i = 0; - for (ClauseListNode* list = m_list1; list; list = list->getNext()) { - generator.emitLabel(labelVector[i++].get()); - statementListEmitCode(list->getClause()->children(), generator, dst); - } - - if (m_defaultClause) { - generator.emitLabel(defaultLabel.get()); - statementListEmitCode(m_defaultClause->children(), generator, dst); - } - - for (ClauseListNode* list = m_list2; list; list = list->getNext()) { - generator.emitLabel(labelVector[i++].get()); - statementListEmitCode(list->getClause()->children(), generator, dst); - } - if (!m_defaultClause) - generator.emitLabel(defaultLabel.get()); - - 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 ----------------------------------- - -RegisterID* SwitchNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::Switch); - - RefPtr<RegisterID> r0 = generator.emitNode(m_expr); - RegisterID* r1 = m_block->emitBytecodeForBlock(generator, r0.get(), dst); - - generator.emitLabel(scope->breakTarget()); - return r1; -} - -// ------------------------------ LabelNode ------------------------------------ - -RegisterID* LabelNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (generator.breakTarget(m_name)) - return emitThrowError(generator, SyntaxError, "Duplicate label: %s.", m_name); - - RefPtr<LabelScope> scope = generator.newLabelScope(LabelScope::NamedLabel, &m_name); - RegisterID* r0 = generator.emitNode(dst, m_statement); - - generator.emitLabel(scope->breakTarget()); - return r0; -} - -// ------------------------------ ThrowNode ------------------------------------ - -RegisterID* ThrowNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - if (dst == generator.ignoredResult()) - dst = 0; - RefPtr<RegisterID> expr = generator.emitNode(m_expr); - generator.emitExpressionInfo(divot(), startOffset(), endOffset()); - generator.emitThrow(expr.get()); - return 0; -} - -// ------------------------------ TryNode -------------------------------------- - -RegisterID* TryNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - // NOTE: The catch and finally blocks must be labeled explicitly, so the - // optimizer knows they may be jumped to from anywhere. - - generator.emitDebugHook(WillExecuteStatement, firstLine(), lastLine()); - - RefPtr<Label> tryStartLabel = generator.newLabel(); - RefPtr<Label> 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); - - if (m_catchBlock) { - RefPtr<Label> catchEndLabel = generator.newLabel(); - - // Normal path: jump over the catch block. - generator.emitJump(catchEndLabel.get()); - - // Uncaught exception path: the catch block. - RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); - RefPtr<RegisterID> exceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get()); - if (m_catchHasEval) { - RefPtr<RegisterID> dynamicScopeObject = generator.emitNewObject(generator.newTemporary()); - generator.emitPutById(dynamicScopeObject.get(), m_exceptionIdent, exceptionRegister.get()); - generator.emitMove(exceptionRegister.get(), dynamicScopeObject.get()); - generator.emitPushScope(exceptionRegister.get()); - } else - generator.emitPushNewScope(exceptionRegister.get(), m_exceptionIdent, exceptionRegister.get()); - generator.emitNode(dst, m_catchBlock); - generator.emitPopScope(); - generator.emitLabel(catchEndLabel.get()); - } - - if (m_finallyBlock) { - 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<Label> finallyEndLabel = generator.newLabel(); - - // Normal path: invoke the finally block, then jump over it. - generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); - generator.emitJump(finallyEndLabel.get()); - - // Uncaught exception path: invoke the finally block, then re-throw the exception. - RefPtr<Label> here = generator.emitLabel(generator.newLabel().get()); - RefPtr<RegisterID> tempExceptionRegister = generator.emitCatch(generator.newTemporary(), tryStartLabel.get(), here.get()); - generator.emitJumpSubroutine(finallyReturnAddr.get(), finallyStart.get()); - generator.emitThrow(tempExceptionRegister.get()); - - // The finally block. - generator.emitLabel(finallyStart.get()); - generator.emitNode(dst, m_finallyBlock); - generator.emitSubroutineReturn(finallyReturnAddr.get()); - - generator.emitLabel(finallyEndLabel.get()); - } - - return dst; + size_t size = m_statements.size(); + return size == 1 ? m_statements[0] : 0; } // -----------------------------ScopeNodeData --------------------------- -ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, int numConstants) +ScopeNodeData::ScopeNodeData(ParserArena& arena, SourceElements* statements, VarStack* varStack, FunctionStack* funcStack, int numConstants) : m_numConstants(numConstants) + , m_statements(statements) { m_arena.swap(arena); if (varStack) m_varStack.swap(*varStack); if (funcStack) m_functionStack.swap(*funcStack); - if (children) - children->releaseContentsIntoVector(m_children); -} - -void ScopeNodeData::markAggregate(MarkStack& markStack) -{ - FunctionStack::iterator end = m_functionStack.end(); - for (FunctionStack::iterator ptr = m_functionStack.begin(); ptr != end; ++ptr) { - FunctionBodyNode* body = (*ptr)->body(); - if (!body->isGenerated()) - continue; - body->generatedBytecode().markAggregate(markStack); - } } // ------------------------------ ScopeNode ----------------------------- @@ -1836,10 +93,6 @@ ScopeNode::ScopeNode(JSGlobalData* globalData) , ParserArenaRefCounted(globalData) , m_features(NoFeatures) { -#if ENABLE(CODEBLOCK_SAMPLING) - if (SamplingTool* sampler = globalData->interpreter->sampler()) - sampler->notifyOfScope(this); -#endif } ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, CodeFeatures features, int numConstants) @@ -1849,10 +102,11 @@ ScopeNode::ScopeNode(JSGlobalData* globalData, const SourceCode& source, SourceE , m_features(features) , m_source(source) { -#if ENABLE(CODEBLOCK_SAMPLING) - if (SamplingTool* sampler = globalData->interpreter->sampler()) - sampler->notifyOfScope(this); -#endif +} + +StatementNode* ScopeNode::singleStatement() const +{ + return m_data->m_statements ? m_data->m_statements->singleStatement() : 0; } // ------------------------------ ProgramNode ----------------------------- @@ -1873,43 +127,6 @@ PassRefPtr<ProgramNode> ProgramNode::create(JSGlobalData* globalData, SourceElem return node.release(); } -RegisterID* ProgramNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); - - RefPtr<RegisterID> dstRegister = generator.newTemporary(); - generator.emitLoad(dstRegister.get(), jsUndefined()); - statementListEmitCode(children(), generator, dstRegister.get()); - - generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); - generator.emitEnd(dstRegister.get()); - return 0; -} - -void ProgramNode::generateBytecode(ScopeChainNode* scopeChainNode) -{ - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - m_code.set(new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider())); - - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(this, globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_code.get())); - generator->generate(); - - destroyData(); -} - -#if ENABLE(JIT) -void ProgramNode::generateJITCode(ScopeChainNode* scopeChainNode) -{ - bytecode(scopeChainNode); - ASSERT(m_code); - ASSERT(!m_jitCode); - JIT::compile(scopeChainNode->globalData, m_code.get()); - ASSERT(m_jitCode); -} -#endif - // ------------------------------ EvalNode ----------------------------- inline EvalNode::EvalNode(JSGlobalData* globalData, SourceElements* children, VarStack* varStack, FunctionStack* funcStack, const SourceCode& source, CodeFeatures features, int numConstants) @@ -1928,128 +145,35 @@ PassRefPtr<EvalNode> EvalNode::create(JSGlobalData* globalData, SourceElements* return node.release(); } -RegisterID* EvalNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(WillExecuteProgram, firstLine(), lastLine()); - - RefPtr<RegisterID> dstRegister = generator.newTemporary(); - generator.emitLoad(dstRegister.get(), jsUndefined()); - statementListEmitCode(children(), generator, dstRegister.get()); - - generator.emitDebugHook(DidExecuteProgram, firstLine(), lastLine()); - generator.emitEnd(dstRegister.get()); - return 0; -} - -void EvalNode::generateBytecode(ScopeChainNode* scopeChainNode) -{ - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - m_code.set(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())); - - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get())); - generator->generate(); - - // Eval code needs to hang on to its declaration stacks to keep declaration info alive until Interpreter::execute time, - // so the entire ScopeNodeData cannot be destoyed. - children().clear(); -} - -EvalCodeBlock& EvalNode::bytecodeForExceptionInfoReparse(ScopeChainNode* scopeChainNode, CodeBlock* codeBlockBeingRegeneratedFrom) -{ - ASSERT(!m_code); - - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - m_code.set(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())); - - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get())); - generator->setRegeneratingForExceptionInfo(codeBlockBeingRegeneratedFrom); - generator->generate(); - - return *m_code; -} - -void EvalNode::markAggregate(MarkStack& markStack) -{ - // We don't need to mark our own CodeBlock as the JSGlobalObject takes care of that - data()->markAggregate(markStack); -} +// ------------------------------ FunctionBodyNode ----------------------------- -#if ENABLE(JIT) -void EvalNode::generateJITCode(ScopeChainNode* scopeChainNode) +FunctionParameters::FunctionParameters(ParameterNode* firstParameter) { - bytecode(scopeChainNode); - ASSERT(m_code); - ASSERT(!m_jitCode); - JIT::compile(scopeChainNode->globalData, m_code.get()); - ASSERT(m_jitCode); + for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam()) + append(parameter->ident()); } -#endif - -// ------------------------------ FunctionBodyNode ----------------------------- inline FunctionBodyNode::FunctionBodyNode(JSGlobalData* globalData) : ScopeNode(globalData) - , m_parameters(0) - , m_parameterCount(0) { } inline 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) -{ -} - -FunctionBodyNode::~FunctionBodyNode() { - for (size_t i = 0; i < m_parameterCount; ++i) - m_parameters[i].~Identifier(); - fastFree(m_parameters); } -void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter) +void FunctionBodyNode::finishParsing(const SourceCode& source, ParameterNode* firstParameter, const Identifier& ident) { - Vector<Identifier> parameters; - for (ParameterNode* parameter = firstParameter; parameter; parameter = parameter->nextParam()) - parameters.append(parameter->ident()); - size_t count = parameters.size(); - setSource(source); - finishParsing(parameters.releaseBuffer(), count); + finishParsing(FunctionParameters::create(firstParameter), ident); } -void FunctionBodyNode::finishParsing(Identifier* parameters, size_t parameterCount) +void FunctionBodyNode::finishParsing(PassRefPtr<FunctionParameters> parameters, const Identifier& ident) { ASSERT(!source().isNull()); m_parameters = parameters; - m_parameterCount = parameterCount; -} - -void FunctionBodyNode::markAggregate(MarkStack& markStack) -{ - if (m_code) - m_code->markAggregate(markStack); -} - -#if ENABLE(JIT) -PassRefPtr<FunctionBodyNode> FunctionBodyNode::createNativeThunk(JSGlobalData* globalData) -{ - RefPtr<FunctionBodyNode> body = new FunctionBodyNode(globalData); - globalData->parser->arena().reset(); - body->m_code.set(new CodeBlock(body.get())); - body->m_jitCode = JITCode(JITCode::HostFunction(globalData->jitStubs.ctiNativeCallThunk())); - return body.release(); -} -#endif - -bool FunctionBodyNode::isHostFunction() const -{ - return m_code && m_code->codeType() == NativeCode; + m_ident = ident; } FunctionBodyNode* FunctionBodyNode::create(JSGlobalData* globalData) @@ -2068,126 +192,4 @@ PassRefPtr<FunctionBodyNode> FunctionBodyNode::create(JSGlobalData* globalData, return node.release(); } -void FunctionBodyNode::generateBytecode(ScopeChainNode* scopeChainNode) -{ - // This branch is only necessary since you can still create a non-stub FunctionBodyNode by - // calling Parser::parse<FunctionBodyNode>(). - if (!data()) - scopeChainNode->globalData->parser->reparseInPlace(scopeChainNode->globalData, this); - ASSERT(data()); - - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset())); - - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get())); - generator->generate(); - - destroyData(); -} - -#if ENABLE(JIT) -void FunctionBodyNode::generateJITCode(ScopeChainNode* scopeChainNode) -{ - bytecode(scopeChainNode); - ASSERT(m_code); - ASSERT(!m_jitCode); - JIT::compile(scopeChainNode->globalData, m_code.get()); - ASSERT(m_jitCode); -} -#endif - -CodeBlock& FunctionBodyNode::bytecodeForExceptionInfoReparse(ScopeChainNode* scopeChainNode, CodeBlock* codeBlockBeingRegeneratedFrom) -{ - ASSERT(!m_code); - - ScopeChain scopeChain(scopeChainNode); - JSGlobalObject* globalObject = scopeChain.globalObject(); - - m_code.set(new CodeBlock(this, FunctionCode, source().provider(), source().startOffset())); - - OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(this, globalObject->debugger(), scopeChain, &m_code->symbolTable(), m_code.get())); - generator->setRegeneratingForExceptionInfo(codeBlockBeingRegeneratedFrom); - generator->generate(); - - return *m_code; -} - -RegisterID* FunctionBodyNode::emitBytecode(BytecodeGenerator& generator, RegisterID*) -{ - generator.emitDebugHook(DidEnterCallFrame, firstLine(), lastLine()); - statementListEmitCode(children(), generator, generator.ignoredResult()); - if (children().size() && children().last()->isBlock()) { - BlockNode* blockNode = static_cast<BlockNode*>(children().last()); - if (blockNode->children().size() && blockNode->children().last()->isReturnNode()) - return 0; - } - - RegisterID* r0 = generator.emitLoad(0, jsUndefined()); - generator.emitDebugHook(WillLeaveCallFrame, firstLine(), lastLine()); - generator.emitReturn(r0); - return 0; -} - -UString FunctionBodyNode::paramString() const -{ - UString s(""); - for (size_t pos = 0; pos < m_parameterCount; ++pos) { - if (!s.isEmpty()) - s += ", "; - s += parameters()[pos].ustring(); - } - - return s; -} - -Identifier* FunctionBodyNode::copyParameters() -{ - Identifier* parameters = static_cast<Identifier*>(fastMalloc(m_parameterCount * sizeof(Identifier))); - VectorCopier<false, Identifier>::uninitializedCopy(m_parameters, m_parameters + m_parameterCount, parameters); - return parameters; -} - -// ------------------------------ FuncDeclNode --------------------------------- - -JSFunction* FuncDeclNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain) -{ - return new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain); -} - -RegisterID* FuncDeclNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - if (dst == generator.ignoredResult()) - dst = 0; - return dst; -} - -// ------------------------------ FuncExprNode --------------------------------- - -RegisterID* FuncExprNode::emitBytecode(BytecodeGenerator& generator, RegisterID* dst) -{ - return generator.emitNewFunctionExpression(generator.finalDestination(dst), this); -} - -JSFunction* FuncExprNode::makeFunction(ExecState* exec, ScopeChainNode* scopeChain) -{ - JSFunction* func = new (exec) JSFunction(exec, m_ident, m_body.get(), scopeChain); - - /* - 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 (!m_ident.isNull()) { - JSStaticScopeObject* functionScopeObject = new (exec) JSStaticScopeObject(exec, m_ident, func, ReadOnly | DontDelete); - func->scope().push(functionScopeObject); - } - - return func; -} - } // namespace JSC diff --git a/JavaScriptCore/parser/Nodes.h b/JavaScriptCore/parser/Nodes.h index 703b384..c216ea8 100644 --- a/JavaScriptCore/parser/Nodes.h +++ b/JavaScriptCore/parser/Nodes.h @@ -34,21 +34,18 @@ #include "SourceCode.h" #include "SymbolTable.h" #include <wtf/MathExtras.h> -#include <wtf/OwnPtr.h> namespace JSC { class ArgumentListNode; - class CodeBlock; class BytecodeGenerator; - class FuncDeclNode; - class EvalCodeBlock; - class JSFunction; - class ProgramCodeBlock; + class FunctionBodyNode; + class Label; class PropertyListNode; class ReadModifyResolveNode; class RegisterID; class ScopeChainNode; + class ScopeNode; typedef unsigned CodeFeatures; @@ -86,8 +83,8 @@ namespace JSC { namespace DeclarationStacks { enum VarAttrs { IsConstant = 1, HasInitializer = 2 }; - typedef Vector<std::pair<Identifier, unsigned> > VarStack; - typedef Vector<FuncDeclNode*> FunctionStack; + typedef Vector<std::pair<const Identifier*, unsigned> > VarStack; + typedef Vector<FunctionBodyNode*> FunctionStack; } struct SwitchInfo { @@ -96,24 +93,23 @@ namespace JSC { SwitchType switchType; }; - class ParserArenaDeletable { - protected: - ParserArenaDeletable() { } + class ParserArenaFreeable { + public: + // ParserArenaFreeable objects are are freed when the arena is deleted. + // Destructors are not called. Clients must not call delete on such objects. + void* operator new(size_t, JSGlobalData*); + }; + class ParserArenaDeletable { public: virtual ~ParserArenaDeletable() { } - // Objects created with this version of new are deleted when the arena is deleted. + // ParserArenaDeletable objects are deleted when the arena is deleted. + // Clients must not call delete directly on such objects. void* operator new(size_t, JSGlobalData*); - - // Objects created with this version of new are not deleted when the arena is deleted. - // Other arrangements must be made. - void* operator new(size_t); - - void operator delete(void*); }; - class ParserArenaRefCounted : public RefCountedCustomAllocated<ParserArenaRefCounted> { + class ParserArenaRefCounted : public RefCounted<ParserArenaRefCounted> { protected: ParserArenaRefCounted(JSGlobalData*); @@ -124,34 +120,14 @@ namespace JSC { } }; - class Node : public ParserArenaDeletable { + class Node : public ParserArenaFreeable { protected: Node(JSGlobalData*); public: - /* - 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. - - dst provides for a crude form of copy propagation. For example, - - x = 1 + virtual ~Node() { } - becomes - - load r[x], 1 - - instead of - - load r0, 1 - mov r[x], r0 - - because the assignment node, "x =", passes r[x] as dst to the number - node, "1". - */ - virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* dst = 0) = 0; + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* destination = 0) = 0; int lineNo() const { return m_line; } @@ -160,9 +136,10 @@ namespace JSC { }; class ExpressionNode : public Node { - public: + protected: ExpressionNode(JSGlobalData*, ResultType = ResultType::unknownType()); + public: virtual bool isNumber() const { return false; } virtual bool isString() const { return false; } virtual bool isNull() const { return false; } @@ -175,23 +152,24 @@ namespace JSC { virtual bool isCommaNode() const { return false; } virtual bool isSimpleArray() const { return false; } virtual bool isAdd() const { return false; } + virtual bool hasConditionContextCodegen() const { return false; } + + virtual void emitBytecodeInConditionContext(BytecodeGenerator&, Label*, Label*, bool) { ASSERT_NOT_REACHED(); } virtual ExpressionNode* stripUnaryPlus() { return this; } ResultType resultDescriptor() const { return m_resultType; } - // This needs to be in public in order to compile using GCC 3.x - typedef enum { EvalOperator, FunctionCall } CallerType; - private: ResultType m_resultType; }; class StatementNode : public Node { - public: + protected: StatementNode(JSGlobalData*); - void setLoc(int line0, int line1); + public: + void setLoc(int firstLine, int lastLine); int firstLine() const { return lineNo(); } int lastLine() const { return m_lastLine; } @@ -229,10 +207,10 @@ namespace JSC { class NumberNode : public ExpressionNode { public: - NumberNode(JSGlobalData*, double v); + NumberNode(JSGlobalData*, double value); - double value() const { return m_double; } - void setValue(double d) { m_double = d; } + double value() const { return m_value; } + void setValue(double value) { m_value = value; } private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); @@ -240,22 +218,23 @@ namespace JSC { virtual bool isNumber() const { return true; } virtual bool isPure(BytecodeGenerator&) const { return true; } - double m_double; + double m_value; }; class StringNode : public ExpressionNode { public: - StringNode(JSGlobalData*, const Identifier& v); + StringNode(JSGlobalData*, const Identifier&); const Identifier& value() { return m_value; } - virtual bool isPure(BytecodeGenerator&) const { return true; } private: + virtual bool isPure(BytecodeGenerator&) const { return true; } + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); virtual bool isString() const { return true; } - Identifier m_value; + const Identifier& m_value; }; class ThrowableExpressionData { @@ -286,8 +265,9 @@ namespace JSC { uint16_t endOffset() const { return m_endOffset; } protected: - RegisterID* emitThrowError(BytecodeGenerator&, ErrorType, const char* msg); - RegisterID* emitThrowError(BytecodeGenerator&, ErrorType, const char* msg, const Identifier&); + RegisterID* emitThrowError(BytecodeGenerator&, ErrorType, const char* message); + RegisterID* emitThrowError(BytecodeGenerator&, ErrorType, const char* message, const UString&); + RegisterID* emitThrowError(BytecodeGenerator&, ErrorType, const char* message, const Identifier&); private: uint32_t m_divot; @@ -298,8 +278,7 @@ namespace JSC { class ThrowableSubExpressionData : public ThrowableExpressionData { public: ThrowableSubExpressionData() - : ThrowableExpressionData() - , m_subexpressionDivotOffset(0) + : m_subexpressionDivotOffset(0) , m_subexpressionEndOffset(0) { } @@ -328,8 +307,7 @@ namespace JSC { class ThrowablePrefixedSubExpressionData : public ThrowableExpressionData { public: ThrowablePrefixedSubExpressionData() - : ThrowableExpressionData() - , m_subexpressionDivotOffset(0) + : m_subexpressionDivotOffset(0) , m_subexpressionStartOffset(0) { } @@ -357,13 +335,13 @@ namespace JSC { class RegExpNode : public ExpressionNode, public ThrowableExpressionData { public: - RegExpNode(JSGlobalData*, const UString& pattern, const UString& flags); + RegExpNode(JSGlobalData*, const Identifier& pattern, const Identifier& flags); private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - UString m_pattern; - UString m_flags; + const Identifier& m_pattern; + const Identifier& m_flags; }; class ThisNode : public ExpressionNode { @@ -387,11 +365,11 @@ namespace JSC { virtual bool isLocation() const { return true; } virtual bool isResolveNode() const { return true; } - Identifier m_ident; + const Identifier& m_ident; int32_t m_startOffset; }; - class ElementNode : public ParserArenaDeletable { + class ElementNode : public ParserArenaFreeable { public: ElementNode(JSGlobalData*, int elision, ExpressionNode*); ElementNode(JSGlobalData*, ElementNode*, int elision, ExpressionNode*); @@ -424,17 +402,18 @@ namespace JSC { bool m_optional; }; - class PropertyNode : public ParserArenaDeletable { + class PropertyNode : public ParserArenaFreeable { public: enum Type { Constant, Getter, Setter }; PropertyNode(JSGlobalData*, const Identifier& name, ExpressionNode* value, Type); + PropertyNode(JSGlobalData*, double name, ExpressionNode* value, Type); const Identifier& name() const { return m_name; } private: friend class PropertyListNode; - Identifier m_name; + const Identifier& m_name; ExpressionNode* m_assign; Type m_type; }; @@ -494,7 +473,7 @@ namespace JSC { virtual bool isDotAccessorNode() const { return true; } ExpressionNode* m_base; - Identifier m_ident; + const Identifier& m_ident; }; class ArgumentListNode : public Node { @@ -509,7 +488,7 @@ namespace JSC { virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); }; - class ArgumentsNode : public ParserArenaDeletable { + class ArgumentsNode : public ParserArenaFreeable { public: ArgumentsNode(JSGlobalData*); ArgumentsNode(JSGlobalData*, ArgumentListNode*); @@ -557,7 +536,7 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - Identifier m_ident; + const Identifier& m_ident; ArgumentsNode* m_args; size_t m_index; // Used by LocalVarFunctionCallNode. size_t m_scopeDepth; // Used by ScopedVarFunctionCallNode and NonLocalVarFunctionCallNode @@ -584,7 +563,7 @@ namespace JSC { protected: ExpressionNode* m_base; - const Identifier m_ident; + const Identifier& m_ident; ArgumentsNode* m_args; }; @@ -609,7 +588,7 @@ namespace JSC { PrePostResolveNode(JSGlobalData*, const Identifier&, unsigned divot, unsigned startOffset, unsigned endOffset); protected: - const Identifier m_ident; + const Identifier& m_ident; }; class PostfixResolveNode : public PrePostResolveNode { @@ -642,7 +621,7 @@ namespace JSC { virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); ExpressionNode* m_base; - Identifier m_ident; + const Identifier& m_ident; Operator m_operator; }; @@ -664,7 +643,7 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - Identifier m_ident; + const Identifier& m_ident; }; class DeleteBracketNode : public ExpressionNode, public ThrowableExpressionData { @@ -686,7 +665,7 @@ namespace JSC { virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); ExpressionNode* m_base; - Identifier m_ident; + const Identifier& m_ident; }; class DeleteValueNode : public ExpressionNode { @@ -718,7 +697,7 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - Identifier m_ident; + const Identifier& m_ident; }; class TypeOfValueNode : public ExpressionNode { @@ -761,7 +740,7 @@ namespace JSC { virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); ExpressionNode* m_base; - Identifier m_ident; + const Identifier& m_ident; Operator m_operator; }; @@ -782,6 +761,7 @@ namespace JSC { protected: ExpressionNode* expr() { return m_expr; } + const ExpressionNode* expr() const { return m_expr; } private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); @@ -813,6 +793,9 @@ namespace JSC { class LogicalNotNode : public UnaryOpNode { public: LogicalNotNode(JSGlobalData*, ExpressionNode*); + private: + void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue); + virtual bool hasConditionContextCodegen() const { return expr()->hasConditionContextCodegen(); } }; class BinaryOpNode : public ExpressionNode { @@ -820,7 +803,7 @@ namespace JSC { BinaryOpNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); BinaryOpNode(JSGlobalData*, ResultType, ExpressionNode* expr1, ExpressionNode* expr2, OpcodeID, bool rightHasAssignments); - RegisterID* emitStrcat(BytecodeGenerator& generator, RegisterID* dst, RegisterID* lhs = 0, ReadModifyResolveNode* emitExpressionInfoForMe = 0); + RegisterID* emitStrcat(BytecodeGenerator& generator, RegisterID* destination, RegisterID* lhs = 0, ReadModifyResolveNode* emitExpressionInfoForMe = 0); private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); @@ -977,6 +960,8 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + void emitBytecodeInConditionContext(BytecodeGenerator&, Label* trueTarget, Label* falseTarget, bool fallThroughMeansTrue); + virtual bool hasConditionContextCodegen() const { return true; } ExpressionNode* m_expr1; ExpressionNode* m_expr2; @@ -1003,7 +988,7 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - Identifier m_ident; + const Identifier& m_ident; ExpressionNode* m_right; size_t m_index; // Used by ReadModifyLocalVarNode. Operator m_operator; @@ -1017,7 +1002,7 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - Identifier m_ident; + const Identifier& m_ident; ExpressionNode* m_right; size_t m_index; // Used by ReadModifyLocalVarNode. bool m_rightHasAssignments; @@ -1060,7 +1045,7 @@ namespace JSC { virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); ExpressionNode* m_base; - Identifier m_ident; + const Identifier& m_ident; ExpressionNode* m_right; bool m_rightHasAssignments; }; @@ -1073,7 +1058,7 @@ namespace JSC { virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); ExpressionNode* m_base; - Identifier m_ident; + const Identifier& m_ident; ExpressionNode* m_right; Operator m_operator : 31; bool m_rightHasAssignments : 1; @@ -1093,10 +1078,12 @@ namespace JSC { typedef Vector<ExpressionNode*, 8> ExpressionVector; - class CommaNode : public ExpressionNode { + class CommaNode : public ExpressionNode, public ParserArenaDeletable { public: CommaNode(JSGlobalData*, ExpressionNode* expr1, ExpressionNode* expr2); + using ParserArenaDeletable::operator new; + void append(ExpressionNode* expr) { m_expressions.append(expr); } private: @@ -1117,7 +1104,7 @@ namespace JSC { virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); virtual RegisterID* emitCodeSingle(BytecodeGenerator&); - Identifier m_ident; + const Identifier& m_ident; public: ConstDeclNode* m_next; @@ -1136,36 +1123,33 @@ namespace JSC { ConstDeclNode* m_next; }; - typedef Vector<StatementNode*> StatementVector; - class SourceElements : public ParserArenaDeletable { public: SourceElements(JSGlobalData*); void append(StatementNode*); - void releaseContentsIntoVector(StatementVector& destination) - { - ASSERT(destination.isEmpty()); - m_statements.swap(destination); - destination.shrinkToFit(); - } + + StatementNode* singleStatement() const; + StatementNode* lastStatement() const; + + void emitBytecode(BytecodeGenerator&, RegisterID* destination); private: - StatementVector m_statements; + Vector<StatementNode*> m_statements; }; class BlockNode : public StatementNode { public: - BlockNode(JSGlobalData*, SourceElements* children); + BlockNode(JSGlobalData*, SourceElements* = 0); - StatementVector& children() { return m_children; } + StatementNode* lastStatement() const; private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); virtual bool isBlock() const { return true; } - StatementVector m_children; + SourceElements* m_statements; }; class EmptyStatementNode : public StatementNode { @@ -1275,7 +1259,7 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - Identifier m_ident; + const Identifier& m_ident; ExpressionNode* m_init; ExpressionNode* m_lexpr; ExpressionNode* m_expr; @@ -1291,7 +1275,7 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - Identifier m_ident; + const Identifier& m_ident; }; class BreakNode : public StatementNode, public ThrowableExpressionData { @@ -1302,7 +1286,7 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - Identifier m_ident; + const Identifier& m_ident; }; class ReturnNode : public StatementNode, public ThrowableExpressionData { @@ -1337,7 +1321,7 @@ namespace JSC { private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - Identifier m_name; + const Identifier& m_name; StatementNode* m_statement; }; @@ -1356,16 +1340,16 @@ namespace JSC { TryNode(JSGlobalData*, StatementNode* tryBlock, const Identifier& exceptionIdent, bool catchHasEval, StatementNode* catchBlock, StatementNode* finallyBlock); private: - virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* dst = 0); + virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); StatementNode* m_tryBlock; - Identifier m_exceptionIdent; + const Identifier& m_exceptionIdent; StatementNode* m_catchBlock; StatementNode* m_finallyBlock; bool m_catchHasEval; }; - class ParameterNode : public ParserArenaDeletable { + class ParameterNode : public ParserArenaFreeable { public: ParameterNode(JSGlobalData*, const Identifier&); ParameterNode(JSGlobalData*, ParameterNode*, const Identifier&); @@ -1374,7 +1358,7 @@ namespace JSC { ParameterNode* nextParam() const { return m_next; } private: - Identifier m_ident; + const Identifier& m_ident; ParameterNode* m_next; }; @@ -1388,9 +1372,7 @@ namespace JSC { VarStack m_varStack; FunctionStack m_functionStack; int m_numConstants; - StatementVector m_children; - - void markAggregate(MarkStack&); + SourceElements* m_statements; }; class ScopeNode : public StatementNode, public ParserArenaRefCounted { @@ -1401,6 +1383,8 @@ namespace JSC { ScopeNode(JSGlobalData*); ScopeNode(JSGlobalData*, const SourceCode&, SourceElements*, VarStack*, FunctionStack*, CodeFeatures, int numConstants); + using ParserArenaRefCounted::operator new; + void adoptData(std::auto_ptr<ScopeNodeData> data) { ASSERT(!data->m_arena.contains(this)); @@ -1426,8 +1410,6 @@ namespace JSC { VarStack& varStack() { ASSERT(m_data); return m_data->m_varStack; } FunctionStack& functionStack() { ASSERT(m_data); return m_data->m_functionStack; } - StatementVector& children() { ASSERT(m_data); return m_data->m_children; } - int neededConstants() { ASSERT(m_data); @@ -1436,33 +1418,13 @@ namespace JSC { return m_data->m_numConstants + 2; } - virtual void markAggregate(MarkStack&) { } + StatementNode* singleStatement() const; -#if ENABLE(JIT) - JITCode& generatedJITCode() - { - ASSERT(m_jitCode); - return m_jitCode; - } - - ExecutablePool* getExecutablePool() - { - return m_jitCode.getExecutablePool(); - } - - void setJITCode(const JITCode jitCode) - { - m_jitCode = jitCode; - } -#endif + void emitStatementsBytecode(BytecodeGenerator&, RegisterID* destination); protected: void setSource(const SourceCode& source) { m_source = source; } -#if ENABLE(JIT) - JITCode m_jitCode; -#endif - private: OwnPtr<ScopeNodeData> m_data; CodeFeatures m_features; @@ -1473,187 +1435,99 @@ namespace JSC { public: static PassRefPtr<ProgramNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); - ProgramCodeBlock& bytecode(ScopeChainNode* scopeChain) - { - if (!m_code) - generateBytecode(scopeChain); - return *m_code; - } - -#if ENABLE(JIT) - JITCode& jitCode(ScopeChainNode* scopeChain) - { - if (!m_jitCode) - generateJITCode(scopeChain); - return m_jitCode; - } -#endif + static const bool scopeIsFunction = false; private: ProgramNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); - void generateBytecode(ScopeChainNode*); virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - -#if ENABLE(JIT) - void generateJITCode(ScopeChainNode*); -#endif - - OwnPtr<ProgramCodeBlock> m_code; }; class EvalNode : public ScopeNode { public: static PassRefPtr<EvalNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); - EvalCodeBlock& bytecode(ScopeChainNode* scopeChain) - { - if (!m_code) - generateBytecode(scopeChain); - return *m_code; - } - - EvalCodeBlock& bytecodeForExceptionInfoReparse(ScopeChainNode*, CodeBlock*); - - virtual void markAggregate(MarkStack&); - -#if ENABLE(JIT) - JITCode& jitCode(ScopeChainNode* scopeChain) - { - if (!m_jitCode) - generateJITCode(scopeChain); - return m_jitCode; - } -#endif + static const bool scopeIsFunction = false; private: EvalNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); - void generateBytecode(ScopeChainNode*); virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); + }; -#if ENABLE(JIT) - void generateJITCode(ScopeChainNode*); -#endif - - OwnPtr<EvalCodeBlock> m_code; + class FunctionParameters : public Vector<Identifier>, public RefCounted<FunctionParameters> { + public: + static PassRefPtr<FunctionParameters> create(ParameterNode* firstParameter) { return adoptRef(new FunctionParameters(firstParameter)); } + + private: + FunctionParameters(ParameterNode*); }; class FunctionBodyNode : public ScopeNode { - friend class JIT; public: -#if ENABLE(JIT) - static PassRefPtr<FunctionBodyNode> createNativeThunk(JSGlobalData*); -#endif static FunctionBodyNode* create(JSGlobalData*); static PassRefPtr<FunctionBodyNode> create(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); - virtual ~FunctionBodyNode(); - const Identifier* parameters() const { return m_parameters; } - size_t parameterCount() const { return m_parameterCount; } - UString paramString() const ; - Identifier* copyParameters(); + FunctionParameters* parameters() const { return m_parameters.get(); } + size_t parameterCount() const { return m_parameters->size(); } virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - bool isGenerated() const - { - return m_code; - } - - bool isHostFunction() const; - - virtual void markAggregate(MarkStack&); - - void finishParsing(const SourceCode&, ParameterNode*); - void finishParsing(Identifier* parameters, size_t parameterCount); + void finishParsing(const SourceCode&, ParameterNode*, const Identifier&); + void finishParsing(PassRefPtr<FunctionParameters>, const Identifier&); - UString toSourceString() const { return source().toString(); } + const Identifier& ident() { return m_ident; } - CodeBlock& bytecodeForExceptionInfoReparse(ScopeChainNode*, CodeBlock*); -#if ENABLE(JIT) - JITCode& jitCode(ScopeChainNode* scopeChain) - { - if (!m_jitCode) - generateJITCode(scopeChain); - return m_jitCode; - } -#endif + static const bool scopeIsFunction = true; - CodeBlock& bytecode(ScopeChainNode* scopeChain) - { - ASSERT(scopeChain); - if (!m_code) - generateBytecode(scopeChain); - return *m_code; - } - - CodeBlock& generatedBytecode() - { - ASSERT(m_code); - return *m_code; - } - private: FunctionBodyNode(JSGlobalData*); FunctionBodyNode(JSGlobalData*, SourceElements*, VarStack*, FunctionStack*, const SourceCode&, CodeFeatures, int numConstants); - void generateBytecode(ScopeChainNode*); -#if ENABLE(JIT) - void generateJITCode(ScopeChainNode*); -#endif - Identifier* m_parameters; - size_t m_parameterCount; - OwnPtr<CodeBlock> m_code; + Identifier m_ident; + RefPtr<FunctionParameters> m_parameters; }; - class FuncExprNode : public ExpressionNode, public ParserArenaRefCounted { + class FuncExprNode : public ExpressionNode { public: FuncExprNode(JSGlobalData*, const Identifier&, FunctionBodyNode* body, const SourceCode& source, ParameterNode* parameter = 0); - JSFunction* makeFunction(ExecState*, ScopeChainNode*); - - FunctionBodyNode* body() { return m_body.get(); } + FunctionBodyNode* body() { return m_body; } private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); virtual bool isFuncExprNode() const { return true; } - Identifier m_ident; - RefPtr<FunctionBodyNode> m_body; + FunctionBodyNode* m_body; }; - class FuncDeclNode : public StatementNode, public ParserArenaRefCounted { + class FuncDeclNode : public StatementNode { public: FuncDeclNode(JSGlobalData*, const Identifier&, FunctionBodyNode*, const SourceCode&, ParameterNode* = 0); - JSFunction* makeFunction(ExecState*, ScopeChainNode*); - - Identifier m_ident; - - FunctionBodyNode* body() { return m_body.get(); } + FunctionBodyNode* body() { return m_body; } private: virtual RegisterID* emitBytecode(BytecodeGenerator&, RegisterID* = 0); - RefPtr<FunctionBodyNode> m_body; + FunctionBodyNode* m_body; }; - class CaseClauseNode : public ParserArenaDeletable { + class CaseClauseNode : public ParserArenaFreeable { public: - CaseClauseNode(JSGlobalData*, ExpressionNode*); - CaseClauseNode(JSGlobalData*, ExpressionNode*, SourceElements*); + CaseClauseNode(JSGlobalData*, ExpressionNode*, SourceElements* = 0); ExpressionNode* expr() const { return m_expr; } - StatementVector& children() { return m_children; } + + void emitBytecode(BytecodeGenerator&, RegisterID* destination); private: ExpressionNode* m_expr; - StatementVector m_children; + SourceElements* m_statements; }; - class ClauseListNode : public ParserArenaDeletable { + class ClauseListNode : public ParserArenaFreeable { public: ClauseListNode(JSGlobalData*, CaseClauseNode*); ClauseListNode(JSGlobalData*, ClauseListNode*, CaseClauseNode*); @@ -1666,11 +1540,11 @@ namespace JSC { ClauseListNode* m_next; }; - class CaseBlockNode : public ParserArenaDeletable { + class CaseBlockNode : public ParserArenaFreeable { public: CaseBlockNode(JSGlobalData*, ClauseListNode* list1, CaseClauseNode* defaultClause, ClauseListNode* list2); - RegisterID* emitBytecodeForBlock(BytecodeGenerator&, RegisterID* input, RegisterID* dst = 0); + RegisterID* emitBytecodeForBlock(BytecodeGenerator&, RegisterID* input, RegisterID* destination); private: SwitchInfo::SwitchType tryOptimizedSwitch(Vector<ExpressionNode*, 8>& literalVector, int32_t& min_num, int32_t& max_num); diff --git a/JavaScriptCore/parser/Parser.cpp b/JavaScriptCore/parser/Parser.cpp index da47ab2..003ca0b 100644 --- a/JavaScriptCore/parser/Parser.cpp +++ b/JavaScriptCore/parser/Parser.cpp @@ -60,7 +60,7 @@ void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg) *errMsg = 0; Lexer& lexer = *globalData->lexer; - lexer.setCode(*m_source); + lexer.setCode(*m_source, m_arena); int parseError = jscyyparse(globalData); bool lexError = lexer.sawError(); @@ -77,33 +77,6 @@ void Parser::parse(JSGlobalData* globalData, int* errLine, UString* errMsg) #endif } -void Parser::reparseInPlace(JSGlobalData* globalData, FunctionBodyNode* functionBodyNode) -{ - ASSERT(!functionBodyNode->data()); - - m_source = &functionBodyNode->source(); - globalData->lexer->setIsReparsing(); - parse(globalData, 0, 0); - ASSERT(m_sourceElements); - - functionBodyNode->adoptData(std::auto_ptr<ScopeNodeData>(new ScopeNodeData(globalData->parser->arena(), - m_sourceElements, - m_varDeclarations ? &m_varDeclarations->data : 0, - m_funcDeclarations ? &m_funcDeclarations->data : 0, - m_numConstants))); - bool usesArguments = functionBodyNode->usesArguments(); - functionBodyNode->setFeatures(m_features); - if (usesArguments && !functionBodyNode->usesArguments()) - functionBodyNode->setUsesArguments(); - - ASSERT(globalData->parser->arena().isEmpty()); - - m_source = 0; - m_sourceElements = 0; - m_varDeclarations = 0; - m_funcDeclarations = 0; -} - void Parser::didFinishParsing(SourceElements* sourceElements, ParserArenaData<DeclarationStacks::VarStack>* varStack, ParserArenaData<DeclarationStacks::FunctionStack>* funcStack, CodeFeatures features, int lastLine, int numConstants) { diff --git a/JavaScriptCore/parser/Parser.h b/JavaScriptCore/parser/Parser.h index 373dc00..894f709 100644 --- a/JavaScriptCore/parser/Parser.h +++ b/JavaScriptCore/parser/Parser.h @@ -24,7 +24,11 @@ #define Parser_h #include "Debugger.h" +#include "Executable.h" +#include "JSGlobalObject.h" +#include "Lexer.h" #include "Nodes.h" +#include "ParserArena.h" #include "SourceProvider.h" #include <wtf/Forward.h> #include <wtf/Noncopyable.h> @@ -41,9 +45,8 @@ namespace JSC { class Parser : public Noncopyable { public: - template <class ParsedNode> PassRefPtr<ParsedNode> parse(ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0); - template <class ParsedNode> PassRefPtr<ParsedNode> reparse(JSGlobalData*, ParsedNode*); - void reparseInPlace(JSGlobalData*, FunctionBodyNode*); + template <class ParsedNode> + PassRefPtr<ParsedNode> parse(JSGlobalData* globalData, Debugger*, ExecState*, const SourceCode& source, int* errLine = 0, UString* errMsg = 0); void didFinishParsing(SourceElements*, ParserArenaData<DeclarationStacks::VarStack>*, ParserArenaData<DeclarationStacks::FunctionStack>*, CodeFeatures features, int lastLine, int numConstants); @@ -63,55 +66,35 @@ namespace JSC { int m_numConstants; }; - template <class ParsedNode> PassRefPtr<ParsedNode> Parser::parse(ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg) + template <class ParsedNode> + PassRefPtr<ParsedNode> Parser::parse(JSGlobalData* globalData, Debugger* debugger, ExecState* debuggerExecState, const SourceCode& source, int* errLine, UString* errMsg) { m_source = &source; - parse(&exec->globalData(), errLine, errMsg); - RefPtr<ParsedNode> result; - if (m_sourceElements) { - result = ParsedNode::create(&exec->globalData(), - m_sourceElements, - 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); - } - - m_arena.reset(); - - m_source = 0; - m_varDeclarations = 0; - m_funcDeclarations = 0; + if (ParsedNode::scopeIsFunction) + globalData->lexer->setIsReparsing(); + parse(globalData, errLine, errMsg); - if (debugger) - debugger->sourceParsed(exec, source, *errLine, *errMsg); - return result.release(); - } - - template <class ParsedNode> PassRefPtr<ParsedNode> Parser::reparse(JSGlobalData* globalData, ParsedNode* oldParsedNode) - { - m_source = &oldParsedNode->source(); - parse(globalData, 0, 0); RefPtr<ParsedNode> result; if (m_sourceElements) { result = ParsedNode::create(globalData, - m_sourceElements, - m_varDeclarations ? &m_varDeclarations->data : 0, - m_funcDeclarations ? &m_funcDeclarations->data : 0, - *m_source, - oldParsedNode->features(), - m_numConstants); + m_sourceElements, + m_varDeclarations ? &m_varDeclarations->data : 0, + m_funcDeclarations ? &m_funcDeclarations->data : 0, + source, + m_features, + m_numConstants); result->setLoc(m_source->firstLine(), m_lastLine); } m_arena.reset(); m_source = 0; + m_sourceElements = 0; m_varDeclarations = 0; m_funcDeclarations = 0; + if (debugger && !ParsedNode::scopeIsFunction) + debugger->sourceParsed(debuggerExecState, source, *errLine, *errMsg); return result.release(); } diff --git a/JavaScriptCore/parser/ParserArena.cpp b/JavaScriptCore/parser/ParserArena.cpp index 2617506..a8e8159 100644 --- a/JavaScriptCore/parser/ParserArena.cpp +++ b/JavaScriptCore/parser/ParserArena.cpp @@ -30,9 +30,39 @@ namespace JSC { +ParserArena::ParserArena() + : m_freeableMemory(0) + , m_freeablePoolEnd(0) + , m_identifierArena(new IdentifierArena) +{ +} + +inline void* ParserArena::freeablePool() +{ + ASSERT(m_freeablePoolEnd); + return m_freeablePoolEnd - freeablePoolSize; +} + +inline void ParserArena::deallocateObjects() +{ + if (m_freeablePoolEnd) + fastFree(freeablePool()); + + size_t size = m_freeablePools.size(); + for (size_t i = 0; i < size; ++i) + fastFree(m_freeablePools[i]); + + size = m_deletableObjects.size(); + for (size_t i = 0; i < size; ++i) { + ParserArenaDeletable* object = m_deletableObjects[i]; + object->~ParserArenaDeletable(); + fastFree(object); + } +} + ParserArena::~ParserArena() { - deleteAllValues(m_deletableObjects); + deallocateObjects(); } bool ParserArena::contains(ParserArenaRefCounted* object) const @@ -52,9 +82,43 @@ void ParserArena::removeLast() void ParserArena::reset() { - deleteAllValues(m_deletableObjects); - m_deletableObjects.shrink(0); - m_refCountedObjects.shrink(0); + // Since this code path is used only when parsing fails, it's not bothering to reuse + // any of the memory the arena allocated. We could improve that later if we want to + // efficiently reuse the same arena. + + deallocateObjects(); + + m_freeableMemory = 0; + m_freeablePoolEnd = 0; + m_identifierArena->clear(); + m_freeablePools.clear(); + m_deletableObjects.clear(); + m_refCountedObjects.clear(); +} + +void ParserArena::allocateFreeablePool() +{ + if (m_freeablePoolEnd) + m_freeablePools.append(freeablePool()); + + char* pool = static_cast<char*>(fastMalloc(freeablePoolSize)); + m_freeableMemory = pool; + m_freeablePoolEnd = pool + freeablePoolSize; + ASSERT(freeablePool() == pool); +} + +bool ParserArena::isEmpty() const +{ + return !m_freeablePoolEnd + && m_identifierArena->isEmpty() + && m_freeablePools.isEmpty() + && m_deletableObjects.isEmpty() + && m_refCountedObjects.isEmpty(); +} + +void ParserArena::derefWithArena(PassRefPtr<ParserArenaRefCounted> object) +{ + m_refCountedObjects.append(object); } } diff --git a/JavaScriptCore/parser/ParserArena.h b/JavaScriptCore/parser/ParserArena.h index 66c8529..eef8e93 100644 --- a/JavaScriptCore/parser/ParserArena.h +++ b/JavaScriptCore/parser/ParserArena.h @@ -26,35 +26,101 @@ #ifndef ParserArena_h #define ParserArena_h -#include <wtf/PassRefPtr.h> -#include <wtf/RefPtr.h> -#include <wtf/Vector.h> +#include "Identifier.h" +#include <wtf/SegmentedVector.h> namespace JSC { class ParserArenaDeletable; class ParserArenaRefCounted; - class ParserArena { + class IdentifierArena : public FastAllocBase { public: + ALWAYS_INLINE const Identifier& makeIdentifier(JSGlobalData*, const UChar* characters, size_t length); + const Identifier& makeNumericIdentifier(JSGlobalData*, double number); + + void clear() { m_identifiers.clear(); } + bool isEmpty() const { return m_identifiers.isEmpty(); } + + private: + typedef SegmentedVector<Identifier, 64> IdentifierVector; + IdentifierVector m_identifiers; + }; + + ALWAYS_INLINE const Identifier& IdentifierArena::makeIdentifier(JSGlobalData* globalData, const UChar* characters, size_t length) + { + m_identifiers.append(Identifier(globalData, characters, length)); + return m_identifiers.last(); + } + + inline const Identifier& IdentifierArena::makeNumericIdentifier(JSGlobalData* globalData, double number) + { + m_identifiers.append(Identifier(globalData, UString::from(number))); + return m_identifiers.last(); + } + + class ParserArena : Noncopyable { + public: + ParserArena(); + ~ParserArena(); + void swap(ParserArena& otherArena) { + std::swap(m_freeableMemory, otherArena.m_freeableMemory); + std::swap(m_freeablePoolEnd, otherArena.m_freeablePoolEnd); + m_identifierArena.swap(otherArena.m_identifierArena); + m_freeablePools.swap(otherArena.m_freeablePools); m_deletableObjects.swap(otherArena.m_deletableObjects); m_refCountedObjects.swap(otherArena.m_refCountedObjects); } - ~ParserArena(); - void deleteWithArena(ParserArenaDeletable* object) { m_deletableObjects.append(object); } - void derefWithArena(PassRefPtr<ParserArenaRefCounted> object) { m_refCountedObjects.append(object); } + void* allocateFreeable(size_t size) + { + ASSERT(size); + ASSERT(size <= freeablePoolSize); + size_t alignedSize = alignSize(size); + ASSERT(alignedSize <= freeablePoolSize); + if (UNLIKELY(static_cast<size_t>(m_freeablePoolEnd - m_freeableMemory) < alignedSize)) + allocateFreeablePool(); + void* block = m_freeableMemory; + m_freeableMemory += alignedSize; + return block; + } + + void* allocateDeletable(size_t size) + { + ParserArenaDeletable* deletable = static_cast<ParserArenaDeletable*>(fastMalloc(size)); + m_deletableObjects.append(deletable); + return deletable; + } + void derefWithArena(PassRefPtr<ParserArenaRefCounted>); bool contains(ParserArenaRefCounted*) const; ParserArenaRefCounted* last() const; void removeLast(); - bool isEmpty() const { return m_deletableObjects.isEmpty() && m_refCountedObjects.isEmpty(); } + bool isEmpty() const; void reset(); + IdentifierArena& identifierArena() { return *m_identifierArena; } + private: + static const size_t freeablePoolSize = 8000; + + static size_t alignSize(size_t size) + { + return (size + sizeof(WTF::AllocAlignmentInteger) - 1) & ~(sizeof(WTF::AllocAlignmentInteger) - 1); + } + + void* freeablePool(); + void allocateFreeablePool(); + void deallocateObjects(); + + char* m_freeableMemory; + char* m_freeablePoolEnd; + + OwnPtr<IdentifierArena> m_identifierArena; + Vector<void*> m_freeablePools; Vector<ParserArenaDeletable*> m_deletableObjects; Vector<RefPtr<ParserArenaRefCounted> > m_refCountedObjects; }; diff --git a/JavaScriptCore/parser/SourceCode.h b/JavaScriptCore/parser/SourceCode.h index 84360b8..9ba4da3 100644 --- a/JavaScriptCore/parser/SourceCode.h +++ b/JavaScriptCore/parser/SourceCode.h @@ -37,7 +37,8 @@ namespace JSC { class SourceCode { public: SourceCode() - : m_startChar(0) + : m_provider(0) + , m_startChar(0) , m_endChar(0) , m_firstLine(0) { diff --git a/JavaScriptCore/pcre/dftables b/JavaScriptCore/pcre/dftables index 8a2d140..1f0ea01 100755 --- a/JavaScriptCore/pcre/dftables +++ b/JavaScriptCore/pcre/dftables @@ -244,7 +244,7 @@ sub readHeaderValues() my ($fh, $tempFile) = tempfile( basename($0) . "-XXXXXXXX", - DIR => File::Spec->tmpdir, + DIR => File::Spec->tmpdir(), SUFFIX => ".in", UNLINK => 0, ); diff --git a/JavaScriptCore/pcre/pcre_exec.cpp b/JavaScriptCore/pcre/pcre_exec.cpp index 16619d4..8ca2eb4 100644 --- a/JavaScriptCore/pcre/pcre_exec.cpp +++ b/JavaScriptCore/pcre/pcre_exec.cpp @@ -2164,14 +2164,14 @@ void Histogram::add(const JSRegExp* re, double elapsedTime) HistogramTimeLogger::HistogramTimeLogger(const JSRegExp* re) : m_re(re) - , m_startTime(getCurrentUTCTimeWithMicroseconds()) + , m_startTime(currentTimeMS()) { } HistogramTimeLogger::~HistogramTimeLogger() { static Histogram histogram; - histogram.add(m_re, getCurrentUTCTimeWithMicroseconds() - m_startTime); + histogram.add(m_re, currentTimeMS() - m_startTime); } #endif diff --git a/JavaScriptCore/profiler/Profile.cpp b/JavaScriptCore/profiler/Profile.cpp index 0a290ce..de75e71 100644 --- a/JavaScriptCore/profiler/Profile.cpp +++ b/JavaScriptCore/profiler/Profile.cpp @@ -29,13 +29,6 @@ #include "ProfileNode.h" #include <stdio.h> -#if PLATFORM(ANDROID) -typedef bool (* Comparator)(const void*, const void*); -namespace std { -extern void sort(const void** start, const void** end, Comparator comp); -} -#endif - namespace JSC { PassRefPtr<Profile> Profile::create(const UString& title, unsigned uid) @@ -115,15 +108,6 @@ void Profile::debugPrintData() const typedef pair<UString::Rep*, unsigned> NameCountPair; -#if PLATFORM(ANDROID) -typedef bool (* NameCountPairComparator)(const NameCountPair&, const NameCountPair&); - -inline void _sort(NameCountPair* start, NameCountPair* end, NameCountPairComparator comp) -{ - std::sort((const void**) start, (const void**) end, (Comparator) comp); -} -#endif - static inline bool functionNameCountPairComparator(const NameCountPair& a, const NameCountPair& b) { return a.second > b.second; @@ -141,11 +125,7 @@ void Profile::debugPrintDataSampleStyle() const NameCountPairVector sortedFunctions(countedFunctions.size()); copyToVector(countedFunctions, sortedFunctions); -#if PLATFORM(ANDROID) - _sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator); -#else std::sort(sortedFunctions.begin(), sortedFunctions.end(), functionNameCountPairComparator); -#endif for (NameCountPairVector::iterator it = sortedFunctions.begin(); it != sortedFunctions.end(); ++it) printf(" %-12d%s\n", (*it).second, UString((*it).first).UTF8String().c_str()); diff --git a/JavaScriptCore/profiler/ProfileGenerator.cpp b/JavaScriptCore/profiler/ProfileGenerator.cpp index 1a061cb..17d37d7 100644 --- a/JavaScriptCore/profiler/ProfileGenerator.cpp +++ b/JavaScriptCore/profiler/ProfileGenerator.cpp @@ -27,6 +27,7 @@ #include "ProfileGenerator.h" #include "CallFrame.h" +#include "CodeBlock.h" #include "JSGlobalObject.h" #include "JSStringRef.h" #include "JSFunction.h" @@ -62,7 +63,7 @@ void ProfileGenerator::addParentForConsoleStart(ExecState* exec) JSValue function; exec->interpreter()->retrieveLastCaller(exec, lineNumber, sourceID, sourceURL, function); - m_currentNode = ProfileNode::create(Profiler::createCallIdentifier(&exec->globalData(), function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get()); + m_currentNode = ProfileNode::create(Profiler::createCallIdentifier(exec, function ? function.toThisObject(exec) : 0, sourceURL, lineNumber), m_head.get(), m_head.get()); m_head->insertNode(m_currentNode.get()); } diff --git a/JavaScriptCore/profiler/ProfileNode.cpp b/JavaScriptCore/profiler/ProfileNode.cpp index 19050aa..02fb7c9 100644 --- a/JavaScriptCore/profiler/ProfileNode.cpp +++ b/JavaScriptCore/profiler/ProfileNode.cpp @@ -37,6 +37,8 @@ #include <windows.h> #endif +using namespace WTF; + namespace JSC { static double getCount() @@ -49,7 +51,7 @@ static double getCount() QueryPerformanceCounter(&counter); return static_cast<double>(counter.QuadPart) / frequency.QuadPart; #else - return WTF::getCurrentUTCTimeWithMicroseconds(); + return currentTimeMS(); #endif } diff --git a/JavaScriptCore/profiler/Profiler.cpp b/JavaScriptCore/profiler/Profiler.cpp index e103fd1..5585d2e 100644 --- a/JavaScriptCore/profiler/Profiler.cpp +++ b/JavaScriptCore/profiler/Profiler.cpp @@ -31,6 +31,7 @@ #include "CommonIdentifiers.h" #include "CallFrame.h" +#include "CodeBlock.h" #include "JSFunction.h" #include "JSGlobalObject.h" #include "Nodes.h" @@ -45,7 +46,7 @@ static const char* GlobalCodeExecution = "(program)"; static const char* AnonymousFunction = "(anonymous function)"; static unsigned ProfilesUID = 0; -static CallIdentifier createCallIdentifierFromFunctionImp(JSGlobalData*, JSFunction*); +static CallIdentifier createCallIdentifierFromFunctionImp(ExecState*, JSFunction*); Profiler* Profiler::s_sharedProfiler = 0; Profiler* Profiler::s_sharedEnabledProfilerReference = 0; @@ -108,14 +109,14 @@ void Profiler::willExecute(ExecState* exec, JSValue function) { ASSERT(!m_currentProfiles.isEmpty()); - dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(&exec->globalData(), function, "", 0), exec->lexicalGlobalObject()->profileGroup()); + dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, createCallIdentifier(exec, function, "", 0), exec->lexicalGlobalObject()->profileGroup()); } void Profiler::willExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber) { ASSERT(!m_currentProfiles.isEmpty()); - CallIdentifier callIdentifier = createCallIdentifier(&exec->globalData(), JSValue(), sourceURL, startingLineNumber); + CallIdentifier callIdentifier = createCallIdentifier(exec, JSValue(), sourceURL, startingLineNumber); dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::willExecute, callIdentifier, exec->lexicalGlobalObject()->profileGroup()); } @@ -124,36 +125,37 @@ void Profiler::didExecute(ExecState* exec, JSValue function) { ASSERT(!m_currentProfiles.isEmpty()); - dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(&exec->globalData(), function, "", 0), exec->lexicalGlobalObject()->profileGroup()); + dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(exec, function, "", 0), exec->lexicalGlobalObject()->profileGroup()); } void Profiler::didExecute(ExecState* exec, const UString& sourceURL, int startingLineNumber) { ASSERT(!m_currentProfiles.isEmpty()); - dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(&exec->globalData(), JSValue(), sourceURL, startingLineNumber), exec->lexicalGlobalObject()->profileGroup()); + dispatchFunctionToProfiles(m_currentProfiles, &ProfileGenerator::didExecute, createCallIdentifier(exec, JSValue(), sourceURL, startingLineNumber), exec->lexicalGlobalObject()->profileGroup()); } -CallIdentifier Profiler::createCallIdentifier(JSGlobalData* globalData, JSValue function, const UString& defaultSourceURL, int defaultLineNumber) +CallIdentifier Profiler::createCallIdentifier(ExecState* exec, JSValue functionValue, const UString& defaultSourceURL, int defaultLineNumber) { - if (!function) + if (!functionValue) return CallIdentifier(GlobalCodeExecution, defaultSourceURL, defaultLineNumber); - if (!function.isObject()) + if (!functionValue.isObject()) return CallIdentifier("(unknown)", defaultSourceURL, defaultLineNumber); - if (asObject(function)->inherits(&JSFunction::info)) { - JSFunction* func = asFunction(function); - if (!func->isHostFunction()) - return createCallIdentifierFromFunctionImp(globalData, func); + if (asObject(functionValue)->inherits(&JSFunction::info)) { + JSFunction* function = asFunction(functionValue); + if (!function->executable()->isHostFunction()) + return createCallIdentifierFromFunctionImp(exec, function); } - if (asObject(function)->inherits(&InternalFunction::info)) - return CallIdentifier(static_cast<InternalFunction*>(asObject(function))->name(globalData), defaultSourceURL, defaultLineNumber); - return CallIdentifier("(" + asObject(function)->className() + " object)", defaultSourceURL, defaultLineNumber); + if (asObject(functionValue)->inherits(&InternalFunction::info)) + return CallIdentifier(static_cast<InternalFunction*>(asObject(functionValue))->name(exec), defaultSourceURL, defaultLineNumber); + return CallIdentifier("(" + asObject(functionValue)->className() + " object)", defaultSourceURL, defaultLineNumber); } -CallIdentifier createCallIdentifierFromFunctionImp(JSGlobalData* globalData, JSFunction* function) +CallIdentifier createCallIdentifierFromFunctionImp(ExecState* exec, JSFunction* function) { - const UString& name = function->calculatedDisplayName(globalData); - return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, function->body()->sourceURL(), function->body()->lineNo()); + ASSERT(!function->isHostFunction()); + const UString& name = function->calculatedDisplayName(exec); + return CallIdentifier(name.isEmpty() ? AnonymousFunction : name, function->jsExecutable()->sourceURL(), function->jsExecutable()->lineNo()); } } // namespace JSC diff --git a/JavaScriptCore/profiler/Profiler.h b/JavaScriptCore/profiler/Profiler.h index 21621bf..4b8b4a0 100644 --- a/JavaScriptCore/profiler/Profiler.h +++ b/JavaScriptCore/profiler/Profiler.h @@ -52,7 +52,7 @@ namespace JSC { } static Profiler* profiler(); - static CallIdentifier createCallIdentifier(JSGlobalData*, JSValue, const UString& sourceURL, int lineNumber); + static CallIdentifier createCallIdentifier(ExecState* exec, JSValue, const UString& sourceURL, int lineNumber); void startProfiling(ExecState*, const UString& title); PassRefPtr<Profile> stopProfiling(ExecState*, const UString& title); diff --git a/JavaScriptCore/runtime/ArgList.h b/JavaScriptCore/runtime/ArgList.h index ab501b6..8e1fdbe 100644 --- a/JavaScriptCore/runtime/ArgList.h +++ b/JavaScriptCore/runtime/ArgList.h @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2007, 2008, 2009 Apple Computer, Inc. + * Copyright (C) 2003, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -23,13 +23,14 @@ #define ArgList_h #include "Register.h" - #include <wtf/HashSet.h> #include <wtf/Noncopyable.h> #include <wtf/Vector.h> namespace JSC { - + + class MarkStack; + class MarkedArgumentBuffer : public Noncopyable { private: static const unsigned inlineCapacity = 8; @@ -103,7 +104,11 @@ namespace JSC { void append(JSValue v) { ASSERT(!m_isReadOnly); - + +#if ENABLE(JSC_ZOMBIES) + ASSERT(!v.isZombie()); +#endif + if (m_isUsingInlineBuffer && m_size < inlineCapacity) { m_vector.uncheckedAppend(v); ++m_size; @@ -186,6 +191,10 @@ namespace JSC { : m_args(args) , m_argCount(argCount) { +#if ENABLE(JSC_ZOMBIES) + for (size_t i = 0; i < argCount; i++) + ASSERT(!m_args[i].isZombie()); +#endif } ArgList(Register* args, int argCount) diff --git a/JavaScriptCore/runtime/Arguments.cpp b/JavaScriptCore/runtime/Arguments.cpp index ec9c450..86a8f0a 100644 --- a/JavaScriptCore/runtime/Arguments.cpp +++ b/JavaScriptCore/runtime/Arguments.cpp @@ -179,6 +179,31 @@ bool Arguments::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNa return JSObject::getOwnPropertySlot(exec, propertyName, slot); } +bool Arguments::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex && i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { + if (i < d->numParameters) { + descriptor.setDescriptor(d->registers[d->firstParameterIndex + i].jsValue(), DontEnum); + } else + descriptor.setDescriptor(d->extraArguments[i - d->numParameters].jsValue(), DontEnum); + return true; + } + + if (propertyName == exec->propertyNames().length && LIKELY(!d->overrodeLength)) { + descriptor.setDescriptor(jsNumber(exec, d->numArguments), DontEnum); + return true; + } + + if (propertyName == exec->propertyNames().callee && LIKELY(!d->overrodeCallee)) { + descriptor.setDescriptor(d->callee, DontEnum); + return true; + } + + return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); +} + void Arguments::put(ExecState* exec, unsigned i, JSValue value, PutPropertySlot& slot) { if (i < d->numArguments && (!d->deletedArguments || !d->deletedArguments[i])) { diff --git a/JavaScriptCore/runtime/Arguments.h b/JavaScriptCore/runtime/Arguments.h index 79fe720..9b674a2 100644 --- a/JavaScriptCore/runtime/Arguments.h +++ b/JavaScriptCore/runtime/Arguments.h @@ -28,6 +28,8 @@ #include "JSFunction.h" #include "JSGlobalObject.h" #include "Interpreter.h" +#include "ObjectConstructor.h" +#include "PrototypeFunction.h" namespace JSC { @@ -83,13 +85,17 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; + private: void getArgumentsData(CallFrame*, JSFunction*&, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual void put(ExecState*, unsigned propertyName, JSValue, PutPropertySlot&); virtual bool deleteProperty(ExecState*, const Identifier& propertyName); @@ -113,18 +119,17 @@ namespace JSC { ALWAYS_INLINE void Arguments::getArgumentsData(CallFrame* callFrame, JSFunction*& function, ptrdiff_t& firstParameterIndex, Register*& argv, int& argc) { function = callFrame->callee(); - - CodeBlock* codeBlock = &function->body()->generatedBytecode(); - int numParameters = codeBlock->m_numParameters; + + int numParameters = function->jsExecutable()->parameterCount(); argc = callFrame->argumentCount(); if (argc <= numParameters) - argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters + 1; // + 1 to skip "this" + argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters; else - argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc + 1; // + 1 to skip "this" + argv = callFrame->registers() - RegisterFile::CallFrameHeaderSize - numParameters - argc; argc -= 1; // - 1 to skip "this" - firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters + 1; // + 1 to skip "this" + firstParameterIndex = -RegisterFile::CallFrameHeaderSize - numParameters; } inline Arguments::Arguments(CallFrame* callFrame) @@ -137,7 +142,7 @@ namespace JSC { int numArguments; getArgumentsData(callFrame, callee, firstParameterIndex, argv, numArguments); - d->numParameters = callee->body()->parameterCount(); + d->numParameters = callee->jsExecutable()->parameterCount(); d->firstParameterIndex = firstParameterIndex; d->numArguments = numArguments; @@ -168,7 +173,7 @@ namespace JSC { : JSObject(callFrame->lexicalGlobalObject()->argumentsStructure()) , d(new ArgumentsData) { - ASSERT(!callFrame->callee()->body()->parameterCount()); + ASSERT(!callFrame->callee()->jsExecutable()->parameterCount()); unsigned numArguments = callFrame->argumentCount() - 1; @@ -214,8 +219,8 @@ namespace JSC { { ASSERT(!d()->registerArray); - size_t numParametersMinusThis = d()->functionBody->generatedBytecode().m_numParameters - 1; - size_t numVars = d()->functionBody->generatedBytecode().m_numVars; + size_t numParametersMinusThis = d()->functionExecutable->generatedBytecode().m_numParameters - 1; + size_t numVars = d()->functionExecutable->generatedBytecode().m_numVars; size_t numLocals = numVars + numParametersMinusThis; if (!numLocals) diff --git a/JavaScriptCore/runtime/ArrayConstructor.cpp b/JavaScriptCore/runtime/ArrayConstructor.cpp index e96bdfc..fb44494 100644 --- a/JavaScriptCore/runtime/ArrayConstructor.cpp +++ b/JavaScriptCore/runtime/ArrayConstructor.cpp @@ -25,15 +25,19 @@ #include "ArrayConstructor.h" #include "ArrayPrototype.h" +#include "Error.h" #include "JSArray.h" #include "JSFunction.h" #include "Lookup.h" +#include "PrototypeFunction.h" namespace JSC { ASSERT_CLASS_FITS_IN_CELL(ArrayConstructor); + +static JSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState*, JSObject*, JSValue, const ArgList&); -ArrayConstructor::ArrayConstructor(ExecState* exec, PassRefPtr<Structure> structure, ArrayPrototype* arrayPrototype) +ArrayConstructor::ArrayConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ArrayPrototype* arrayPrototype, Structure* prototypeFunctionStructure) : InternalFunction(&exec->globalData(), structure, Identifier(exec, arrayPrototype->classInfo()->className)) { // ECMA 15.4.3.1 Array.prototype @@ -41,9 +45,12 @@ ArrayConstructor::ArrayConstructor(ExecState* exec, PassRefPtr<Structure> struct // no. of arguments for constructor putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete); + + // ES5 + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().isArray, arrayConstructorIsArray), DontEnum); } -static JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) +static inline JSObject* constructArrayWithSizeQuirk(ExecState* exec, const ArgList& args) { // a single numeric argument denotes the array size (!) if (args.size() == 1 && args.at(0).isNumber()) { @@ -82,4 +89,9 @@ CallType ArrayConstructor::getCallData(CallData& callData) return CallTypeHost; } +JSValue JSC_HOST_CALL arrayConstructorIsArray(ExecState*, JSObject*, JSValue, const ArgList& args) +{ + return jsBoolean(args.at(0).inherits(&JSArray::info)); +} + } // namespace JSC diff --git a/JavaScriptCore/runtime/ArrayConstructor.h b/JavaScriptCore/runtime/ArrayConstructor.h index 8300d8c..6d25400 100644 --- a/JavaScriptCore/runtime/ArrayConstructor.h +++ b/JavaScriptCore/runtime/ArrayConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class ArrayConstructor : public InternalFunction { public: - ArrayConstructor(ExecState*, PassRefPtr<Structure>, ArrayPrototype*); + ArrayConstructor(ExecState*, NonNullPassRefPtr<Structure>, ArrayPrototype*, Structure*); virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); diff --git a/JavaScriptCore/runtime/ArrayPrototype.cpp b/JavaScriptCore/runtime/ArrayPrototype.cpp index 807e59a..5b359e7 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.cpp +++ b/JavaScriptCore/runtime/ArrayPrototype.cpp @@ -67,7 +67,7 @@ static JSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState*, JSObject*, JS namespace JSC { -static inline bool isNumericCompareFunction(CallType callType, const CallData& callData) +static inline bool isNumericCompareFunction(ExecState* exec, CallType callType, const CallData& callData) { if (callType != CallTypeJS) return false; @@ -75,10 +75,10 @@ static inline bool isNumericCompareFunction(CallType callType, const CallData& c #if ENABLE(JIT) // If the JIT is enabled then we need to preserve the invariant that every // function with a CodeBlock also has JIT code. - callData.js.functionBody->jitCode(callData.js.scopeChain); - CodeBlock& codeBlock = callData.js.functionBody->generatedBytecode(); + callData.js.functionExecutable->jitCode(exec, callData.js.scopeChain); + CodeBlock& codeBlock = callData.js.functionExecutable->generatedBytecode(); #else - CodeBlock& codeBlock = callData.js.functionBody->bytecode(callData.js.scopeChain); + CodeBlock& codeBlock = callData.js.functionExecutable->bytecode(exec, callData.js.scopeChain); #endif return codeBlock.isNumericCompareFunction(); @@ -115,7 +115,7 @@ const ClassInfo ArrayPrototype::info = {"Array", &JSArray::info, 0, ExecState::a */ // ECMA 15.4.4 -ArrayPrototype::ArrayPrototype(PassRefPtr<Structure> structure) +ArrayPrototype::ArrayPrototype(NonNullPassRefPtr<Structure> structure) : JSArray(structure) { } @@ -125,6 +125,11 @@ bool ArrayPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& prope return getStaticFunctionSlot<JSArray>(exec, ExecState::arrayTable(exec), this, propertyName, slot); } +bool ArrayPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticFunctionDescriptor<JSArray>(exec, ExecState::arrayTable(exec), this, propertyName, descriptor); +} + // ------------------------------ Array Functions ---------------------------- // Helper function @@ -144,10 +149,11 @@ static void putProperty(ExecState* exec, JSObject* obj, const Identifier& proper JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&JSArray::info)) + bool isRealArray = isJSArray(&exec->globalData(), thisValue); + if (!isRealArray && !thisValue.inherits(&JSArray::info)) return throwError(exec, TypeError); - JSObject* thisObj = asArray(thisValue); - + JSArray* thisObj = asArray(thisValue); + HashSet<JSObject*>& arrayVisitedElements = exec->globalData().arrayVisitedElements; if (arrayVisitedElements.size() >= MaxSecondaryThreadReentryDepth) { if (!isMainThread() || arrayVisitedElements.size() >= MaxMainThreadReentryDepth) @@ -158,39 +164,53 @@ JSValue JSC_HOST_CALL arrayProtoFuncToString(ExecState* exec, JSObject*, JSValue if (alreadyVisited) return jsEmptyString(exec); // return an empty string, avoiding infinite recursion. - Vector<UChar, 256> strBuffer; unsigned length = thisObj->get(exec, exec->propertyNames().length).toUInt32(exec); + unsigned totalSize = length ? length - 1 : 0; + Vector<RefPtr<UString::Rep>, 256> strBuffer(length); for (unsigned k = 0; k < length; k++) { - if (k >= 1) - strBuffer.append(','); - if (!strBuffer.data()) { - JSObject* error = Error::create(exec, GeneralError, "Out of memory"); - exec->setException(error); - break; - } - - JSValue element = thisObj->get(exec, k); + JSValue element; + if (isRealArray && thisObj->canGetIndex(k)) + element = thisObj->getIndex(k); + else + element = thisObj->get(exec, k); + if (element.isUndefinedOrNull()) continue; - + UString str = element.toString(exec); - strBuffer.append(str.data(), str.size()); - + strBuffer[k] = str.rep(); + totalSize += str.size(); + if (!strBuffer.data()) { JSObject* error = Error::create(exec, GeneralError, "Out of memory"); exec->setException(error); } - + if (exec->hadException()) break; } arrayVisitedElements.remove(thisObj); - return jsString(exec, UString(strBuffer.data(), strBuffer.data() ? strBuffer.size() : 0)); + if (!totalSize) + return jsEmptyString(exec); + Vector<UChar> buffer; + buffer.reserveCapacity(totalSize); + if (!buffer.data()) + return throwError(exec, GeneralError, "Out of memory"); + + for (unsigned i = 0; i < length; i++) { + if (i) + buffer.append(','); + if (RefPtr<UString::Rep> rep = strBuffer[i]) + buffer.append(rep->data(), rep->size()); + } + ASSERT(buffer.size() == totalSize); + unsigned finalSize = buffer.size(); + return jsString(exec, UString(buffer.releaseBuffer(), finalSize, false)); } JSValue JSC_HOST_CALL arrayProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&JSArray::info)) + if (!thisValue.inherits(&JSArray::info)) return throwError(exec, TypeError); JSObject* thisObj = asArray(thisValue); @@ -298,7 +318,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncConcat(ExecState* exec, JSObject*, JSValue t ArgList::const_iterator it = args.begin(); ArgList::const_iterator end = args.end(); while (1) { - if (curArg.isObject(&JSArray::info)) { + if (curArg.inherits(&JSArray::info)) { unsigned length = curArg.get(exec, exec->propertyNames().length).toUInt32(exec); JSObject* curObject = curArg.toObject(exec); for (unsigned k = 0; k < length; ++k) { @@ -456,7 +476,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncSort(ExecState* exec, JSObject*, JSValue thi CallType callType = function.getCallData(callData); if (thisObj->classInfo() == &JSArray::info) { - if (isNumericCompareFunction(callType, callData)) + if (isNumericCompareFunction(exec, callType, callData)) asArray(thisObj)->sortNumeric(exec, function, callType, callData); else if (callType != CallTypeNone) asArray(thisObj)->sort(exec, function, callType, callData); @@ -725,8 +745,8 @@ JSValue JSC_HOST_CALL arrayProtoFuncEvery(ExecState* exec, JSObject*, JSValue th cachedCall.setArgument(0, array->getIndex(k)); cachedCall.setArgument(1, jsNumber(exec, k)); cachedCall.setArgument(2, thisObj); - - if (!cachedCall.call().toBoolean(exec)) + JSValue result = cachedCall.call(); + if (!result.toBoolean(cachedCall.newCallFrame(exec))) return jsBoolean(false); } } @@ -826,8 +846,8 @@ JSValue JSC_HOST_CALL arrayProtoFuncSome(ExecState* exec, JSObject*, JSValue thi cachedCall.setArgument(0, array->getIndex(k)); cachedCall.setArgument(1, jsNumber(exec, k)); cachedCall.setArgument(2, thisObj); - - if (cachedCall.call().toBoolean(exec)) + JSValue result = cachedCall.call(); + if (result.toBoolean(cachedCall.newCallFrame(exec))) return jsBoolean(true); } } @@ -1014,7 +1034,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncIndexOf(ExecState* exec, JSObject*, JSValue JSValue e = getProperty(exec, thisObj, index); if (!e) continue; - if (JSValue::strictEqual(searchElement, e)) + if (JSValue::strictEqual(exec, searchElement, e)) return jsNumber(exec, index); } @@ -1045,7 +1065,7 @@ JSValue JSC_HOST_CALL arrayProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSVa JSValue e = getProperty(exec, thisObj, index); if (!e) continue; - if (JSValue::strictEqual(searchElement, e)) + if (JSValue::strictEqual(exec, searchElement, e)) return jsNumber(exec, index); } diff --git a/JavaScriptCore/runtime/ArrayPrototype.h b/JavaScriptCore/runtime/ArrayPrototype.h index 2165089..e52914c 100644 --- a/JavaScriptCore/runtime/ArrayPrototype.h +++ b/JavaScriptCore/runtime/ArrayPrototype.h @@ -28,9 +28,10 @@ namespace JSC { class ArrayPrototype : public JSArray { public: - explicit ArrayPrototype(PassRefPtr<Structure>); + explicit ArrayPrototype(NonNullPassRefPtr<Structure>); bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; diff --git a/JavaScriptCore/runtime/BatchedTransitionOptimizer.h b/JavaScriptCore/runtime/BatchedTransitionOptimizer.h index b9f738f..74089a5 100644 --- a/JavaScriptCore/runtime/BatchedTransitionOptimizer.h +++ b/JavaScriptCore/runtime/BatchedTransitionOptimizer.h @@ -38,12 +38,12 @@ namespace JSC { : m_object(object) { if (!m_object->structure()->isDictionary()) - m_object->setStructure(Structure::toDictionaryTransition(m_object->structure())); + m_object->setStructure(Structure::toCacheableDictionaryTransition(m_object->structure())); } ~BatchedTransitionOptimizer() { - m_object->setStructure(Structure::fromDictionaryTransition(m_object->structure())); + m_object->flattenDictionaryObject(); } private: diff --git a/JavaScriptCore/runtime/BooleanConstructor.cpp b/JavaScriptCore/runtime/BooleanConstructor.cpp index 9fcba37..b0d8df3 100644 --- a/JavaScriptCore/runtime/BooleanConstructor.cpp +++ b/JavaScriptCore/runtime/BooleanConstructor.cpp @@ -28,7 +28,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(BooleanConstructor); -BooleanConstructor::BooleanConstructor(ExecState* exec, PassRefPtr<Structure> structure, BooleanPrototype* booleanPrototype) +BooleanConstructor::BooleanConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, BooleanPrototype* booleanPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, booleanPrototype->classInfo()->className)) { putDirectWithoutTransition(exec->propertyNames().prototype, booleanPrototype, DontEnum | DontDelete | ReadOnly); diff --git a/JavaScriptCore/runtime/BooleanConstructor.h b/JavaScriptCore/runtime/BooleanConstructor.h index d9f51ab..1d8a26a 100644 --- a/JavaScriptCore/runtime/BooleanConstructor.h +++ b/JavaScriptCore/runtime/BooleanConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class BooleanConstructor : public InternalFunction { public: - BooleanConstructor(ExecState*, PassRefPtr<Structure>, BooleanPrototype*); + BooleanConstructor(ExecState*, NonNullPassRefPtr<Structure>, BooleanPrototype*); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/JavaScriptCore/runtime/BooleanObject.cpp b/JavaScriptCore/runtime/BooleanObject.cpp index 01f695a..c9b3846 100644 --- a/JavaScriptCore/runtime/BooleanObject.cpp +++ b/JavaScriptCore/runtime/BooleanObject.cpp @@ -27,7 +27,7 @@ ASSERT_CLASS_FITS_IN_CELL(BooleanObject); const ClassInfo BooleanObject::info = { "Boolean", 0, 0, 0 }; -BooleanObject::BooleanObject(PassRefPtr<Structure> structure) +BooleanObject::BooleanObject(NonNullPassRefPtr<Structure> structure) : JSWrapperObject(structure) { } diff --git a/JavaScriptCore/runtime/BooleanObject.h b/JavaScriptCore/runtime/BooleanObject.h index cfd55fe..69c2e51 100644 --- a/JavaScriptCore/runtime/BooleanObject.h +++ b/JavaScriptCore/runtime/BooleanObject.h @@ -27,10 +27,15 @@ namespace JSC { class BooleanObject : public JSWrapperObject { public: - explicit BooleanObject(PassRefPtr<Structure>); + explicit BooleanObject(NonNullPassRefPtr<Structure>); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); + } }; BooleanObject* asBooleanObject(JSValue); diff --git a/JavaScriptCore/runtime/BooleanPrototype.cpp b/JavaScriptCore/runtime/BooleanPrototype.cpp index 703a568..8d338f9 100644 --- a/JavaScriptCore/runtime/BooleanPrototype.cpp +++ b/JavaScriptCore/runtime/BooleanPrototype.cpp @@ -37,7 +37,7 @@ static JSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState*, JSObject*, JSVa // ECMA 15.6.4 -BooleanPrototype::BooleanPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) +BooleanPrototype::BooleanPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) : BooleanObject(structure) { setInternalValue(jsBoolean(false)); @@ -59,7 +59,7 @@ JSValue JSC_HOST_CALL booleanProtoFuncToString(ExecState* exec, JSObject*, JSVal if (thisValue == jsBoolean(true)) return jsNontrivialString(exec, "true"); - if (!thisValue.isObject(&BooleanObject::info)) + if (!thisValue.inherits(&BooleanObject::info)) return throwError(exec, TypeError); if (asBooleanObject(thisValue)->internalValue() == jsBoolean(false)) @@ -74,7 +74,7 @@ JSValue JSC_HOST_CALL booleanProtoFuncValueOf(ExecState* exec, JSObject*, JSValu if (thisValue.isBoolean()) return thisValue; - if (!thisValue.isObject(&BooleanObject::info)) + if (!thisValue.inherits(&BooleanObject::info)) return throwError(exec, TypeError); return asBooleanObject(thisValue)->internalValue(); diff --git a/JavaScriptCore/runtime/BooleanPrototype.h b/JavaScriptCore/runtime/BooleanPrototype.h index 16f80b5..cc69b3f 100644 --- a/JavaScriptCore/runtime/BooleanPrototype.h +++ b/JavaScriptCore/runtime/BooleanPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class BooleanPrototype : public BooleanObject { public: - BooleanPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + BooleanPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); }; } // namespace JSC diff --git a/JavaScriptCore/runtime/CallData.h b/JavaScriptCore/runtime/CallData.h index d5b0172..24c19f9 100644 --- a/JavaScriptCore/runtime/CallData.h +++ b/JavaScriptCore/runtime/CallData.h @@ -35,7 +35,7 @@ namespace JSC { class ArgList; class ExecState; - class FunctionBodyNode; + class FunctionExecutable; class JSObject; class JSValue; class ScopeChainNode; @@ -53,7 +53,7 @@ namespace JSC { NativeFunction function; } native; struct { - FunctionBodyNode* functionBody; + FunctionExecutable* functionExecutable; ScopeChainNode* scopeChain; } js; }; diff --git a/JavaScriptCore/runtime/Collector.cpp b/JavaScriptCore/runtime/Collector.cpp index c188016..1630a58 100644 --- a/JavaScriptCore/runtime/Collector.cpp +++ b/JavaScriptCore/runtime/Collector.cpp @@ -23,13 +23,16 @@ #include "ArgList.h" #include "CallFrame.h" +#include "CodeBlock.h" #include "CollectorHeapIterator.h" #include "Interpreter.h" +#include "JSArray.h" #include "JSGlobalObject.h" #include "JSLock.h" #include "JSONObject.h" #include "JSString.h" #include "JSValue.h" +#include "JSZombie.h" #include "MarkStack.h" #include "Nodes.h" #include "Tracing.h" @@ -58,11 +61,18 @@ #elif PLATFORM(WIN_OS) #include <windows.h> +#include <malloc.h> + +#elif PLATFORM(HAIKU) + +#include <OS.h> #elif PLATFORM(UNIX) #include <stdlib.h> +#if !PLATFORM(HAIKU) #include <sys/mman.h> +#endif #include <unistd.h> #if PLATFORM(SOLARIS) @@ -75,9 +85,15 @@ #include <pthread_np.h> #endif +#if PLATFORM(QNX) +#include <fcntl.h> +#include <sys/procfs.h> +#include <stdio.h> +#include <errno.h> +#endif + #endif -#define DEBUG_COLLECTOR 0 #define COLLECT_ON_EVERY_ALLOCATION 0 using std::max; @@ -86,7 +102,6 @@ namespace JSC { // tunable parameters -const size_t SPARE_EMPTY_BLOCKS = 2; const size_t GROWTH_FACTOR = 2; const size_t LOW_WATER_FACTOR = 4; const size_t ALLOCATIONS_PER_COLLECTION = 4000; @@ -99,18 +114,12 @@ const size_t MAX_NUM_BLOCKS = 256; // Max size of collector heap set to 16 MB static RHeap* userChunk = 0; #endif -static void freeHeap(CollectorHeap*); - #if ENABLE(JSC_MULTIPLE_THREADS) #if PLATFORM(DARWIN) typedef mach_port_t PlatformThread; #elif PLATFORM(WIN_OS) -struct PlatformThread { - PlatformThread(DWORD _id, HANDLE _handle) : id(_id), handle(_handle) {} - DWORD id; - HANDLE handle; -}; +typedef HANDLE PlatformThread; #endif class Heap::Thread { @@ -186,11 +195,13 @@ void Heap::destroy() sweep<PrimaryHeap>(); // No need to sweep number heap, because the JSNumber destructor doesn't do anything. - +#if ENABLE(JSC_ZOMBIES) + ASSERT(primaryHeap.numLiveObjects == primaryHeap.numZombies); +#else ASSERT(!primaryHeap.numLiveObjects); - - freeHeap(&primaryHeap); - freeHeap(&numberHeap); +#endif + freeBlocks(&primaryHeap); + freeBlocks(&numberHeap); #if ENABLE(JSC_MULTIPLE_THREADS) if (m_currentThreadRegistrar) { @@ -210,7 +221,7 @@ void Heap::destroy() } template <HeapType heapType> -static NEVER_INLINE CollectorBlock* allocateBlock() +NEVER_INLINE CollectorBlock* Heap::allocateBlock() { #if PLATFORM(DARWIN) vm_address_t address = 0; @@ -224,9 +235,15 @@ static NEVER_INLINE CollectorBlock* allocateBlock() uintptr_t address = reinterpret_cast<uintptr_t>(mask); memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE); +#elif PLATFORM(WINCE) + void* address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); #elif PLATFORM(WIN_OS) - // windows virtual address granularity is naturally 64k - LPVOID address = VirtualAlloc(NULL, BLOCK_SIZE, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); +#if COMPILER(MINGW) + void* address = __mingw_aligned_malloc(BLOCK_SIZE, BLOCK_SIZE); +#else + void* address = _aligned_malloc(BLOCK_SIZE, BLOCK_SIZE); +#endif + memset(address, 0, BLOCK_SIZE); #elif HAVE(POSIX_MEMALIGN) void* address; posix_memalign(&address, BLOCK_SIZE, BLOCK_SIZE); @@ -258,18 +275,58 @@ static NEVER_INLINE CollectorBlock* allocateBlock() address += adjust; memset(reinterpret_cast<void*>(address), 0, BLOCK_SIZE); #endif - reinterpret_cast<CollectorBlock*>(address)->type = heapType; - return reinterpret_cast<CollectorBlock*>(address); + + CollectorBlock* block = reinterpret_cast<CollectorBlock*>(address); + block->freeList = block->cells; + block->heap = this; + block->type = heapType; + + CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; + size_t numBlocks = heap.numBlocks; + if (heap.usedBlocks == numBlocks) { + static const size_t maxNumBlocks = ULONG_MAX / sizeof(CollectorBlock*) / GROWTH_FACTOR; + if (numBlocks > maxNumBlocks) + CRASH(); + numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR); + heap.numBlocks = numBlocks; + heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock*))); + } + heap.blocks[heap.usedBlocks++] = block; + + return block; } -static void freeBlock(CollectorBlock* block) +template <HeapType heapType> +NEVER_INLINE void Heap::freeBlock(size_t block) +{ + CollectorHeap& heap = heapType == PrimaryHeap ? primaryHeap : numberHeap; + + freeBlock(heap.blocks[block]); + + // swap with the last block so we compact as we go + heap.blocks[block] = heap.blocks[heap.usedBlocks - 1]; + heap.usedBlocks--; + + if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) { + heap.numBlocks = heap.numBlocks / GROWTH_FACTOR; + heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock*))); + } +} + +NEVER_INLINE void Heap::freeBlock(CollectorBlock* block) { #if PLATFORM(DARWIN) vm_deallocate(current_task(), reinterpret_cast<vm_address_t>(block), BLOCK_SIZE); #elif PLATFORM(SYMBIAN) userChunk->Free(reinterpret_cast<TAny*>(block)); -#elif PLATFORM(WIN_OS) +#elif PLATFORM(WINCE) VirtualFree(block, 0, MEM_RELEASE); +#elif PLATFORM(WIN_OS) +#if COMPILER(MINGW) + __mingw_aligned_free(block); +#else + _aligned_free(block); +#endif #elif HAVE(POSIX_MEMALIGN) free(block); #else @@ -277,7 +334,7 @@ static void freeBlock(CollectorBlock* block) #endif } -static void freeHeap(CollectorHeap* heap) +void Heap::freeBlocks(CollectorHeap* heap) { for (size_t i = 0; i < heap->usedBlocks; ++i) if (heap->blocks[i]) @@ -370,38 +427,23 @@ collect: #ifndef NDEBUG heap.operationInProgress = NoOperation; #endif - bool collected = collect(); + bool foundGarbage = collect(); + numLiveObjects = heap.numLiveObjects; + usedBlocks = heap.usedBlocks; + i = heap.firstBlockWithPossibleSpace; #ifndef NDEBUG heap.operationInProgress = Allocation; #endif - if (collected) { - numLiveObjects = heap.numLiveObjects; - usedBlocks = heap.usedBlocks; - i = heap.firstBlockWithPossibleSpace; + if (foundGarbage) goto scan; - } - } - - // didn't find a block, and GC didn't reclaim anything, need to allocate a new block - size_t numBlocks = heap.numBlocks; - if (usedBlocks == numBlocks) { - static const size_t maxNumBlocks = ULONG_MAX / sizeof(CollectorBlock*) / GROWTH_FACTOR; - if (numBlocks > maxNumBlocks) - CRASH(); - numBlocks = max(MIN_ARRAY_SIZE, numBlocks * GROWTH_FACTOR); - heap.numBlocks = numBlocks; - heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, numBlocks * sizeof(CollectorBlock*))); } + // didn't find a block, and GC didn't reclaim anything, need to allocate a new block targetBlock = reinterpret_cast<Block*>(allocateBlock<heapType>()); - targetBlock->freeList = targetBlock->cells; - targetBlock->heap = this; + heap.firstBlockWithPossibleSpace = heap.usedBlocks - 1; targetBlockUsedCells = 0; - heap.blocks[usedBlocks] = reinterpret_cast<CollectorBlock*>(targetBlock); - heap.usedBlocks = usedBlocks + 1; - heap.firstBlockWithPossibleSpace = usedBlocks; } - + // find a free spot in the block and detach it from the free list Cell* newCell = targetBlock->freeList; @@ -486,6 +528,33 @@ static void* getStackBase(void* previousFrame) } #endif +#if PLATFORM(QNX) +static inline void *currentThreadStackBaseQNX() +{ + static void* stackBase = 0; + static size_t stackSize = 0; + static pthread_t stackThread; + pthread_t thread = pthread_self(); + if (stackBase == 0 || thread != stackThread) { + struct _debug_thread_info threadInfo; + memset(&threadInfo, 0, sizeof(threadInfo)); + threadInfo.tid = pthread_self(); + int fd = open("/proc/self", O_RDONLY); + if (fd == -1) { + LOG_ERROR("Unable to open /proc/self (errno: %d)", errno); + return 0; + } + devctl(fd, DCMD_PROC_TIDSTATUS, &threadInfo, sizeof(threadInfo), 0); + close(fd); + stackBase = reinterpret_cast<void*>(threadInfo.stkbase); + stackSize = threadInfo.stksize; + ASSERT(stackBase); + stackThread = thread; + } + return static_cast<char*>(stackBase) + stackSize; +} +#endif + static inline void* currentThreadStackBase() { #if PLATFORM(DARWIN) @@ -511,6 +580,8 @@ static inline void* currentThreadStackBase() : "=r" (pTib) ); return static_cast<void*>(pTib->StackBase); +#elif PLATFORM(QNX) + return currentThreadStackBaseQNX(); #elif PLATFORM(SOLARIS) stack_t s; thr_stksegment(&s); @@ -529,6 +600,10 @@ static inline void* currentThreadStackBase() stackBase = (void*)info.iBase; } return (void*)stackBase; +#elif PLATFORM(HAIKU) + thread_info threadInfo; + get_thread_info(find_thread(NULL), &threadInfo); + return threadInfo.stack_end; #elif PLATFORM(UNIX) static void* stackBase = 0; static size_t stackSize = 0; @@ -570,8 +645,7 @@ static inline PlatformThread getCurrentPlatformThread() #if PLATFORM(DARWIN) return pthread_mach_thread_np(pthread_self()); #elif PLATFORM(WIN_OS) - HANDLE threadHandle = pthread_getw32threadhandle_np(pthread_self()); - return PlatformThread(GetCurrentThreadId(), threadHandle); + return pthread_getw32threadhandle_np(pthread_self()); #endif } @@ -587,6 +661,8 @@ void Heap::makeUsableFromMultipleThreads() void Heap::registerThread() { + ASSERT(!m_globalData->mainThreadOnly || isMainThread()); + if (!m_currentThreadRegistrar || pthread_getspecific(m_currentThreadRegistrar)) return; @@ -683,7 +759,7 @@ void Heap::markConservatively(MarkStack& markStack, void* start, void* end) // 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) { + if (reinterpret_cast<CollectorCell*>(xAsBits)->u.freeCell.zeroIfFree) { markStack.append(reinterpret_cast<JSCell*>(xAsBits)); markStack.drain(); } @@ -704,10 +780,16 @@ void NEVER_INLINE Heap::markCurrentThreadConservativelyInternal(MarkStack& markS markConservatively(markStack, stackPointer, stackBase); } +#if COMPILER(GCC) +#define REGISTER_BUFFER_ALIGNMENT __attribute__ ((aligned (sizeof(void*)))) +#else +#define REGISTER_BUFFER_ALIGNMENT +#endif + void Heap::markCurrentThreadConservatively(MarkStack& markStack) { // setjmp forces volatile registers onto the stack - jmp_buf registers; + jmp_buf registers REGISTER_BUFFER_ALIGNMENT; #if COMPILER(MSVC) #pragma warning(push) #pragma warning(disable: 4611) @@ -727,7 +809,7 @@ static inline void suspendThread(const PlatformThread& platformThread) #if PLATFORM(DARWIN) thread_suspend(platformThread); #elif PLATFORM(WIN_OS) - SuspendThread(platformThread.handle); + SuspendThread(platformThread); #else #error Need a way to suspend threads on this platform #endif @@ -738,7 +820,7 @@ static inline void resumeThread(const PlatformThread& platformThread) #if PLATFORM(DARWIN) thread_resume(platformThread); #elif PLATFORM(WIN_OS) - ResumeThread(platformThread.handle); + ResumeThread(platformThread); #else #error Need a way to resume threads on this platform #endif @@ -802,7 +884,7 @@ static size_t getPlatformThreadRegisters(const PlatformThread& platformThread, P #elif PLATFORM(WIN_OS) && PLATFORM(X86) regs.ContextFlags = CONTEXT_INTEGER | CONTEXT_CONTROL | CONTEXT_SEGMENTS; - GetThreadContext(platformThread.handle, ®s); + GetThreadContext(platformThread, ®s); return sizeof(CONTEXT); #else #error Need a way to get thread registers on this platform @@ -896,16 +978,6 @@ void Heap::markStackObjectsConservatively(MarkStack& markStack) #endif } -void Heap::setGCProtectNeedsLocking() -{ - // Most clients do not need to call this, with the notable exception of WebCore. - // Clients that use shared heap have JSLock protection, while others are supposed - // to do explicit locking. WebCore violates this contract in Database code, - // which calls gcUnprotect from a secondary thread. - if (!m_protectedValuesMutex) - m_protectedValuesMutex.set(new Mutex); -} - void Heap::protect(JSValue k) { ASSERT(k); @@ -914,13 +986,7 @@ void Heap::protect(JSValue k) if (!k.isCell()) return; - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - m_protectedValues.add(k.asCell()); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); } void Heap::unprotect(JSValue k) @@ -931,38 +997,16 @@ void Heap::unprotect(JSValue k) if (!k.isCell()) return; - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - m_protectedValues.remove(k.asCell()); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); -} - -Heap* Heap::heap(JSValue v) -{ - if (!v.isCell()) - return 0; - return Heap::cellBlock(v.asCell())->heap; } void Heap::markProtectedObjects(MarkStack& markStack) { - 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()) { - markStack.append(val); - markStack.drain(); - } + markStack.append(it->first); + markStack.drain(); } - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); } template <HeapType heapType> size_t Heap::sweep() @@ -995,17 +1039,26 @@ template <HeapType heapType> size_t Heap::sweep() // assumes the object has a valid vptr.) if (cell->u.freeCell.zeroIfFree == 0) continue; - +#if ENABLE(JSC_ZOMBIES) + if (!imp->isZombie()) { + const ClassInfo* info = imp->classInfo(); + imp->~JSCell(); + new (imp) JSZombie(info, JSZombie::leakedZombieStructure()); + heap.numZombies++; + } +#else imp->~JSCell(); +#endif } - - --usedCells; --numLiveObjects; +#if !ENABLE(JSC_ZOMBIES) + --usedCells; // put cell on the free list cell->u.freeCell.zeroIfFree = 0; cell->u.freeCell.next = freeList - (cell + 1); freeList = cell; +#endif } } } else { @@ -1018,8 +1071,18 @@ template <HeapType heapType> size_t Heap::sweep() if (!curBlock->marked.get(i >> HeapConstants<heapType>::bitmapShift)) { if (heapType != NumberHeap) { JSCell* imp = reinterpret_cast<JSCell*>(cell); +#if ENABLE(JSC_ZOMBIES) + if (!imp->isZombie()) { + const ClassInfo* info = imp->classInfo(); + imp->~JSCell(); + new (imp) JSZombie(info, JSZombie::leakedZombieStructure()); + heap.numZombies++; + } +#else imp->~JSCell(); +#endif } +#if !ENABLE(JSC_ZOMBIES) --usedCells; --numLiveObjects; @@ -1027,6 +1090,7 @@ template <HeapType heapType> size_t Heap::sweep() cell->u.freeCell.zeroIfFree = 0; cell->u.freeCell.next = freeList - (cell + 1); freeList = cell; +#endif } } } @@ -1036,31 +1100,34 @@ template <HeapType heapType> size_t Heap::sweep() curBlock->freeList = freeList; curBlock->marked.clearAll(); - if (usedCells == 0) { - emptyBlocks++; - if (emptyBlocks > SPARE_EMPTY_BLOCKS) { -#if !DEBUG_COLLECTOR - freeBlock(reinterpret_cast<CollectorBlock*>(curBlock)); -#endif - // swap with the last block so we compact as we go - heap.blocks[block] = heap.blocks[heap.usedBlocks - 1]; - heap.usedBlocks--; - block--; // Don't move forward a step in this case - - if (heap.numBlocks > MIN_ARRAY_SIZE && heap.usedBlocks < heap.numBlocks / LOW_WATER_FACTOR) { - heap.numBlocks = heap.numBlocks / GROWTH_FACTOR; - heap.blocks = static_cast<CollectorBlock**>(fastRealloc(heap.blocks, heap.numBlocks * sizeof(CollectorBlock*))); - } - } - } + if (!usedCells) + ++emptyBlocks; } if (heap.numLiveObjects != numLiveObjects) heap.firstBlockWithPossibleSpace = 0; - + heap.numLiveObjects = numLiveObjects; heap.numLiveObjectsAtLastCollect = numLiveObjects; heap.extraCost = 0; + + if (!emptyBlocks) + return numLiveObjects; + + size_t neededCells = 1.25f * (numLiveObjects + max(ALLOCATIONS_PER_COLLECTION, numLiveObjects)); + size_t neededBlocks = (neededCells + HeapConstants<heapType>::cellsPerBlock - 1) / HeapConstants<heapType>::cellsPerBlock; + for (size_t block = 0; block < heap.usedBlocks; block++) { + if (heap.usedBlocks <= neededBlocks) + break; + + Block* curBlock = reinterpret_cast<Block*>(heap.blocks[block]); + if (curBlock->usedCells) + continue; + + freeBlock<heapType>(block); + block--; // Don't move forward a step in this case + } + return numLiveObjects; } @@ -1087,12 +1154,12 @@ bool Heap::collect() markProtectedObjects(markStack); if (m_markListSet && m_markListSet->size()) MarkedArgumentBuffer::markLists(markStack, *m_markListSet); - if (m_globalData->exception && !m_globalData->exception.marked()) + if (m_globalData->exception) markStack.append(m_globalData->exception); m_globalData->interpreter->registerFile().markCallFrames(markStack, this); - m_globalData->smallStrings.mark(); - if (m_globalData->scopeNodeBeingReparsed) - m_globalData->scopeNodeBeingReparsed->markAggregate(markStack); + m_globalData->smallStrings.markChildren(markStack); + if (m_globalData->functionCodeBlockBeingReparsed) + m_globalData->functionCodeBlockBeingReparsed->markAggregate(markStack); if (m_globalData->firstStringifierToMark) JSONObject::markStringifiers(markStack, m_globalData->firstStringifierToMark); @@ -1151,9 +1218,6 @@ size_t Heap::globalObjectCount() size_t Heap::protectedGlobalObjectCount() { - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - size_t count = 0; if (JSGlobalObject* head = m_globalData->head) { JSGlobalObject* o = head; @@ -1164,23 +1228,12 @@ size_t Heap::protectedGlobalObjectCount() } while (o != head); } - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); - return count; } size_t Heap::protectedObjectCount() { - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - - size_t result = m_protectedValues.size(); - - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); - - return result; + return m_protectedValues.size(); } static const char* typeName(JSCell* cell) @@ -1193,8 +1246,12 @@ static const char* typeName(JSCell* cell) #endif if (cell->isGetterSetter()) return "gettersetter"; + if (cell->isAPIValueWrapper()) + return "value wrapper"; + if (cell->isPropertyNameIterator()) + return "for-in iterator"; ASSERT(cell->isObject()); - const ClassInfo* info = static_cast<JSObject*>(cell)->classInfo(); + const ClassInfo* info = cell->classInfo(); return info ? info->className : "Object"; } @@ -1202,16 +1259,10 @@ HashCountedSet<const char*>* Heap::protectedObjectTypeCounts() { HashCountedSet<const char*>* counts = new HashCountedSet<const char*>; - if (m_protectedValuesMutex) - m_protectedValuesMutex->lock(); - ProtectCountSet::iterator end = m_protectedValues.end(); for (ProtectCountSet::iterator it = m_protectedValues.begin(); it != end; ++it) counts->add(typeName(it->first)); - if (m_protectedValuesMutex) - m_protectedValuesMutex->unlock(); - return counts; } diff --git a/JavaScriptCore/runtime/Collector.h b/JavaScriptCore/runtime/Collector.h index 877f890..9128701 100644 --- a/JavaScriptCore/runtime/Collector.h +++ b/JavaScriptCore/runtime/Collector.h @@ -60,6 +60,9 @@ namespace JSC { size_t numLiveObjects; size_t numLiveObjectsAtLastCollect; size_t extraCost; +#if ENABLE(JSC_ZOMBIES) + size_t numZombies; +#endif OperationInProgress operationInProgress; }; @@ -71,14 +74,6 @@ namespace JSC { void destroy(); -#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - // We can inline these functions because everything is compiled as - // one file, so the heapAllocate template definitions are available. - // However, allocateNumber is used via jsNumberCell outside JavaScriptCore. - // Thus allocateNumber needs to provide a non-inline version too. - void* inlineAllocateNumber(size_t s) { return heapAllocate<NumberHeap>(s); } - void* inlineAllocate(size_t s) { return heapAllocate<PrimaryHeap>(s); } -#endif void* allocateNumber(size_t); void* allocate(size_t); @@ -96,11 +91,11 @@ namespace JSC { }; Statistics statistics() const; - void setGCProtectNeedsLocking(); void protect(JSValue); void unprotect(JSValue); static Heap* heap(JSValue); // 0 for immediate values + static Heap* heap(JSCell*); size_t globalObjectCount(); size_t protectedObjectCount(); @@ -133,6 +128,11 @@ namespace JSC { Heap(JSGlobalData*); ~Heap(); + template <HeapType heapType> NEVER_INLINE CollectorBlock* allocateBlock(); + template <HeapType heapType> NEVER_INLINE void freeBlock(size_t); + NEVER_INLINE void freeBlock(CollectorBlock*); + void freeBlocks(CollectorHeap*); + void recordExtraCost(size_t); void markProtectedObjects(MarkStack&); void markCurrentThreadConservatively(MarkStack&); @@ -145,7 +145,6 @@ namespace JSC { CollectorHeap primaryHeap; CollectorHeap numberHeap; - OwnPtr<Mutex> m_protectedValuesMutex; // Only non-null if the client explicitly requested it via setGCPrtotectNeedsLocking(). ProtectCountSet m_protectedValues; HashSet<MarkedArgumentBuffer*>* m_markListSet; @@ -175,7 +174,11 @@ namespace JSC { #endif template<> struct CellSize<sizeof(uint64_t)> { static const size_t m_value = 64; }; - const size_t BLOCK_SIZE = 16 * 4096; // 64k +#if PLATFORM(WINCE) || PLATFORM(SYMBIAN) + const size_t BLOCK_SIZE = 64 * 1024; // 64k +#else + const size_t BLOCK_SIZE = 64 * 4096; // 256k +#endif // derived constants const size_t BLOCK_OFFSET_MASK = BLOCK_SIZE - 1; diff --git a/JavaScriptCore/runtime/CommonIdentifiers.h b/JavaScriptCore/runtime/CommonIdentifiers.h index 148d3dd..abe5038 100644 --- a/JavaScriptCore/runtime/CommonIdentifiers.h +++ b/JavaScriptCore/runtime/CommonIdentifiers.h @@ -37,17 +37,26 @@ macro(callee) \ macro(caller) \ macro(compile) \ + macro(configurable) \ macro(constructor) \ + macro(create) \ + macro(defineProperty) \ + macro(defineProperties) \ + macro(enumerable) \ macro(eval) \ macro(exec) \ macro(fromCharCode) \ macro(global) \ + macro(get) \ macro(getPrototypeOf) \ + macro(getOwnPropertyDescriptor) \ macro(hasOwnProperty) \ macro(ignoreCase) \ macro(index) \ macro(input) \ + macro(isArray) \ macro(isPrototypeOf) \ + macro(keys) \ macro(length) \ macro(message) \ macro(multiline) \ @@ -56,6 +65,7 @@ macro(parse) \ macro(propertyIsEnumerable) \ macro(prototype) \ + macro(set) \ macro(source) \ macro(test) \ macro(toExponential) \ @@ -66,7 +76,9 @@ macro(toPrecision) \ macro(toString) \ macro(UTC) \ + macro(value) \ macro(valueOf) \ + macro(writable) \ macro(displayName) namespace JSC { diff --git a/JavaScriptCore/runtime/Completion.cpp b/JavaScriptCore/runtime/Completion.cpp index b8b1581..2507698 100644 --- a/JavaScriptCore/runtime/Completion.cpp +++ b/JavaScriptCore/runtime/Completion.cpp @@ -31,40 +31,33 @@ #include "Debugger.h" #include <stdio.h> -#if !PLATFORM(WIN_OS) -#include <unistd.h> -#endif - namespace JSC { Completion checkSyntax(ExecState* exec, const SourceCode& source) { JSLock lock(exec); - int errLine; - UString errMsg; + RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source); + JSObject* error = program->checkSyntax(exec); + if (error) + return Completion(Throw, error); - RefPtr<ProgramNode> progNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); - if (!progNode) - return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url())); return Completion(Normal); } Completion evaluate(ExecState* exec, ScopeChain& scopeChain, const SourceCode& source, JSValue thisValue) { JSLock lock(exec); - - int errLine; - UString errMsg; - RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); - if (!programNode) - return Completion(Throw, Error::create(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url())); + RefPtr<ProgramExecutable> program = ProgramExecutable::create(exec, source); + JSObject* error = program->compile(exec, scopeChain.node()); + if (error) + return Completion(Throw, error); JSObject* thisObj = (!thisValue || thisValue.isUndefinedOrNull()) ? exec->dynamicGlobalObject() : thisValue.toObject(exec); JSValue exception; - JSValue result = exec->interpreter()->execute(programNode.get(), exec, scopeChain.node(), thisObj, &exception); + JSValue result = exec->interpreter()->execute(program.get(), exec, scopeChain.node(), thisObj, &exception); if (exception) { if (exception.isObject() && asObject(exception)->isWatchdogException()) diff --git a/JavaScriptCore/runtime/ConstructData.h b/JavaScriptCore/runtime/ConstructData.h index 9d580d5..6b954a6 100644 --- a/JavaScriptCore/runtime/ConstructData.h +++ b/JavaScriptCore/runtime/ConstructData.h @@ -33,7 +33,7 @@ namespace JSC { class ArgList; class ExecState; - class FunctionBodyNode; + class FunctionExecutable; class JSObject; class JSValue; class ScopeChainNode; @@ -51,7 +51,7 @@ namespace JSC { NativeConstructor function; } native; struct { - FunctionBodyNode* functionBody; + FunctionExecutable* functionExecutable; ScopeChainNode* scopeChain; } js; }; diff --git a/JavaScriptCore/runtime/DateConstructor.cpp b/JavaScriptCore/runtime/DateConstructor.cpp index 2f52cff..61ec4c5 100644 --- a/JavaScriptCore/runtime/DateConstructor.cpp +++ b/JavaScriptCore/runtime/DateConstructor.cpp @@ -57,7 +57,7 @@ static JSValue JSC_HOST_CALL dateParse(ExecState*, JSObject*, JSValue, const Arg static JSValue JSC_HOST_CALL dateNow(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL dateUTC(ExecState*, JSObject*, JSValue, const ArgList&); -DateConstructor::DateConstructor(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, DatePrototype* datePrototype) +DateConstructor::DateConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, DatePrototype* datePrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, datePrototype->classInfo()->className)) { putDirectWithoutTransition(exec->propertyNames().prototype, datePrototype, DontEnum|DontDelete|ReadOnly); @@ -77,14 +77,14 @@ JSObject* constructDate(ExecState* exec, const ArgList& args) double value; if (numArgs == 0) // new Date() ECMA 15.9.3.3 - value = getCurrentUTCTime(); + value = jsCurrentTime(); else if (numArgs == 1) { - if (args.at(0).isObject(&DateInstance::info)) + if (args.at(0).inherits(&DateInstance::info)) value = asDateInstance(args.at(0))->internalNumber(); else { JSValue primitive = args.at(0).toPrimitive(exec); if (primitive.isString()) - value = parseDate(primitive.getString()); + value = parseDate(exec, primitive.getString(exec)); else value = primitive.toNumber(exec); } @@ -108,13 +108,11 @@ JSObject* constructDate(ExecState* exec, const ArgList& args) t.second = args.at(5).toInt32(exec); t.isDST = -1; double ms = (numArgs >= 7) ? args.at(6).toNumber(exec) : 0; - value = gregorianDateTimeToMS(t, ms, false); + value = gregorianDateTimeToMS(exec, t, ms, false); } } - DateInstance* result = new (exec) DateInstance(exec->lexicalGlobalObject()->dateStructure()); - result->setInternalValue(jsNumber(exec, timeClip(value))); - return result; + return new (exec) DateInstance(exec, value); } static JSObject* constructWithDateConstructor(ExecState* exec, JSObject*, const ArgList& args) @@ -134,8 +132,8 @@ static JSValue JSC_HOST_CALL callDate(ExecState* exec, JSObject*, JSValue, const time_t localTime = time(0); tm localTM; getLocalTime(&localTime, &localTM); - GregorianDateTime ts(localTM); - return jsNontrivialString(exec, formatDate(ts) + " " + formatTime(ts, false)); + GregorianDateTime ts(exec, localTM); + return jsNontrivialString(exec, formatDate(ts) + " " + formatTime(ts)); } CallType DateConstructor::getCallData(CallData& callData) @@ -146,12 +144,12 @@ CallType DateConstructor::getCallData(CallData& callData) static JSValue JSC_HOST_CALL dateParse(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, parseDate(args.at(0).toString(exec))); + return jsNumber(exec, parseDate(exec, args.at(0).toString(exec))); } static JSValue JSC_HOST_CALL dateNow(ExecState* exec, JSObject*, JSValue, const ArgList&) { - return jsNumber(exec, getCurrentUTCTime()); + return jsNumber(exec, jsCurrentTime()); } static JSValue JSC_HOST_CALL dateUTC(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -175,7 +173,7 @@ static JSValue JSC_HOST_CALL dateUTC(ExecState* exec, JSObject*, JSValue, const t.minute = args.at(4).toInt32(exec); t.second = args.at(5).toInt32(exec); double ms = (n >= 7) ? args.at(6).toNumber(exec) : 0; - return jsNumber(exec, gregorianDateTimeToMS(t, ms, true)); + return jsNumber(exec, gregorianDateTimeToMS(exec, t, ms, true)); } } // namespace JSC diff --git a/JavaScriptCore/runtime/DateConstructor.h b/JavaScriptCore/runtime/DateConstructor.h index dcef3cc..10e450e 100644 --- a/JavaScriptCore/runtime/DateConstructor.h +++ b/JavaScriptCore/runtime/DateConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class DateConstructor : public InternalFunction { public: - DateConstructor(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure, DatePrototype*); + DateConstructor(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure, DatePrototype*); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/JavaScriptCore/runtime/DateConversion.cpp b/JavaScriptCore/runtime/DateConversion.cpp index a725478..b9d0e02 100644 --- a/JavaScriptCore/runtime/DateConversion.cpp +++ b/JavaScriptCore/runtime/DateConversion.cpp @@ -43,6 +43,7 @@ #include "config.h" #include "DateConversion.h" +#include "CallFrame.h" #include "UString.h" #include <wtf/DateMath.h> #include <wtf/StringExtras.h> @@ -51,9 +52,14 @@ using namespace WTF; namespace JSC { -double parseDate(const UString &date) +double parseDate(ExecState* exec, const UString &date) { - return parseDateFromNullTerminatedCharacters(date.UTF8String().c_str()); + if (date == exec->globalData().cachedDateString) + return exec->globalData().cachedDateStringValue; + double value = parseDateFromNullTerminatedCharacters(exec, date.UTF8String().c_str()); + exec->globalData().cachedDateString = date; + exec->globalData().cachedDateStringValue = value; + return value; } UString formatDate(const GregorianDateTime &t) @@ -74,28 +80,31 @@ UString formatDateUTCVariant(const GregorianDateTime &t) return buffer; } -UString formatTime(const GregorianDateTime &t, bool utc) +UString formatTime(const GregorianDateTime &t) { char buffer[100]; - if (utc) { - snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second); - } else { - int offset = abs(gmtoffset(t)); - char timeZoneName[70]; - struct tm gtm = t; - strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); + int offset = abs(gmtoffset(t)); + char timeZoneName[70]; + struct tm gtm = t; + strftime(timeZoneName, sizeof(timeZoneName), "%Z", >m); - if (timeZoneName[0]) { - snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)", - t.hour, t.minute, t.second, - gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, timeZoneName); - } else { - snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d", - t.hour, t.minute, t.second, - gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60); - } + if (timeZoneName[0]) { + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d (%s)", + t.hour, t.minute, t.second, + gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60, timeZoneName); + } else { + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT%c%02d%02d", + t.hour, t.minute, t.second, + gmtoffset(t) < 0 ? '-' : '+', offset / (60*60), (offset / 60) % 60); } return UString(buffer); } +UString formatTimeUTC(const GregorianDateTime &t) +{ + char buffer[100]; + snprintf(buffer, sizeof(buffer), "%02d:%02d:%02d GMT", t.hour, t.minute, t.second); + return UString(buffer); +} + } // namespace JSC diff --git a/JavaScriptCore/runtime/DateConversion.h b/JavaScriptCore/runtime/DateConversion.h index 0d12815..dc980d3 100644 --- a/JavaScriptCore/runtime/DateConversion.h +++ b/JavaScriptCore/runtime/DateConversion.h @@ -42,18 +42,17 @@ #ifndef DateConversion_h #define DateConversion_h -namespace WTF { - struct GregorianDateTime; -} - namespace JSC { +class ExecState; class UString; +struct GregorianDateTime; -double parseDate(const UString&); -UString formatDate(const WTF::GregorianDateTime&); -UString formatDateUTCVariant(const WTF::GregorianDateTime&); -UString formatTime(const WTF::GregorianDateTime&, bool inputIsUTC); +double parseDate(ExecState* exec, const UString&); +UString formatDate(const GregorianDateTime&); +UString formatDateUTCVariant(const GregorianDateTime&); +UString formatTime(const GregorianDateTime&); +UString formatTimeUTC(const GregorianDateTime&); } // namespace JSC diff --git a/JavaScriptCore/runtime/DateInstance.cpp b/JavaScriptCore/runtime/DateInstance.cpp index 62791ae..77a92be 100644 --- a/JavaScriptCore/runtime/DateInstance.cpp +++ b/JavaScriptCore/runtime/DateInstance.cpp @@ -22,6 +22,8 @@ #include "config.h" #include "DateInstance.h" +#include "JSGlobalObject.h" + #include <math.h> #include <wtf/DateMath.h> #include <wtf/MathExtras.h> @@ -30,89 +32,50 @@ using namespace WTF; namespace JSC { -struct DateInstance::Cache { - double m_gregorianDateTimeCachedForMS; - GregorianDateTime m_cachedGregorianDateTime; - double m_gregorianDateTimeUTCCachedForMS; - GregorianDateTime m_cachedGregorianDateTimeUTC; -}; - const ClassInfo DateInstance::info = {"Date", 0, 0, 0}; -DateInstance::DateInstance(PassRefPtr<Structure> structure) +DateInstance::DateInstance(ExecState* exec, NonNullPassRefPtr<Structure> structure) : JSWrapperObject(structure) - , m_cache(0) { + setInternalValue(jsNaN(exec)); } -DateInstance::~DateInstance() +DateInstance::DateInstance(ExecState* exec, double time) + : JSWrapperObject(exec->lexicalGlobalObject()->dateStructure()) { - delete m_cache; + setInternalValue(jsNumber(exec, timeClip(time))); } -void DateInstance::msToGregorianDateTime(double milli, bool outputIsUTC, GregorianDateTime& t) const -{ - if (!m_cache) { - m_cache = new Cache; - m_cache->m_gregorianDateTimeCachedForMS = NaN; - m_cache->m_gregorianDateTimeUTCCachedForMS = NaN; - } - - if (outputIsUTC) { - if (m_cache->m_gregorianDateTimeUTCCachedForMS != milli) { - WTF::msToGregorianDateTime(milli, true, m_cache->m_cachedGregorianDateTimeUTC); - m_cache->m_gregorianDateTimeUTCCachedForMS = milli; - } - t.copyFrom(m_cache->m_cachedGregorianDateTimeUTC); - } else { - if (m_cache->m_gregorianDateTimeCachedForMS != milli) { - WTF::msToGregorianDateTime(milli, false, m_cache->m_cachedGregorianDateTime); - m_cache->m_gregorianDateTimeCachedForMS = milli; - } - t.copyFrom(m_cache->m_cachedGregorianDateTime); - } -} - -bool DateInstance::getTime(GregorianDateTime& t, int& offset) const +const GregorianDateTime* DateInstance::calculateGregorianDateTime(ExecState* exec) const { double milli = internalNumber(); if (isnan(milli)) - return false; - - msToGregorianDateTime(milli, false, t); - offset = gmtoffset(t); - return true; + return 0; + + if (!m_data) + m_data = exec->globalData().dateInstanceCache.add(milli); + + if (m_data->m_gregorianDateTimeCachedForMS != milli) { + msToGregorianDateTime(exec, milli, false, m_data->m_cachedGregorianDateTime); + m_data->m_gregorianDateTimeCachedForMS = milli; + } + return &m_data->m_cachedGregorianDateTime; } -bool DateInstance::getUTCTime(GregorianDateTime& t) const +const GregorianDateTime* DateInstance::calculateGregorianDateTimeUTC(ExecState* exec) const { double milli = internalNumber(); if (isnan(milli)) - return false; - - msToGregorianDateTime(milli, true, t); - return true; -} + return 0; -bool DateInstance::getTime(double& milli, int& offset) const -{ - milli = internalNumber(); - if (isnan(milli)) - return false; - - GregorianDateTime t; - msToGregorianDateTime(milli, false, t); - offset = gmtoffset(t); - return true; -} + if (!m_data) + m_data = exec->globalData().dateInstanceCache.add(milli); -bool DateInstance::getUTCTime(double& milli) const -{ - milli = internalNumber(); - if (isnan(milli)) - return false; - - return true; + if (m_data->m_gregorianDateTimeUTCCachedForMS != milli) { + msToGregorianDateTime(exec, milli, true, m_data->m_cachedGregorianDateTimeUTC); + m_data->m_gregorianDateTimeUTCCachedForMS = milli; + } + return &m_data->m_cachedGregorianDateTimeUTC; } } // namespace JSC diff --git a/JavaScriptCore/runtime/DateInstance.h b/JavaScriptCore/runtime/DateInstance.h index 3b73521..44b7521 100644 --- a/JavaScriptCore/runtime/DateInstance.h +++ b/JavaScriptCore/runtime/DateInstance.h @@ -31,27 +31,41 @@ namespace JSC { class DateInstance : public JSWrapperObject { public: - explicit DateInstance(PassRefPtr<Structure>); - virtual ~DateInstance(); + DateInstance(ExecState*, double); + explicit DateInstance(ExecState*, NonNullPassRefPtr<Structure>); double internalNumber() const { return internalValue().uncheckedGetNumber(); } - bool getTime(WTF::GregorianDateTime&, int& offset) const; - bool getUTCTime(WTF::GregorianDateTime&) const; - bool getTime(double& milliseconds, int& offset) const; - bool getUTCTime(double& milliseconds) const; - - static const ClassInfo info; - - void msToGregorianDateTime(double, bool outputIsUTC, WTF::GregorianDateTime&) const; + static JS_EXPORTDATA const ClassInfo info; + + const GregorianDateTime* gregorianDateTime(ExecState* exec) const + { + if (m_data && m_data->m_gregorianDateTimeCachedForMS == internalNumber()) + return &m_data->m_cachedGregorianDateTime; + return calculateGregorianDateTime(exec); + } + + const GregorianDateTime* gregorianDateTimeUTC(ExecState* exec) const + { + if (m_data && m_data->m_gregorianDateTimeUTCCachedForMS == internalNumber()) + return &m_data->m_cachedGregorianDateTimeUTC; + return calculateGregorianDateTimeUTC(exec); + } + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); + } + + protected: + static const unsigned StructureFlags = OverridesMarkChildren | JSWrapperObject::StructureFlags; private: + const GregorianDateTime* calculateGregorianDateTime(ExecState*) const; + const GregorianDateTime* calculateGregorianDateTimeUTC(ExecState*) const; virtual const ClassInfo* classInfo() const { return &info; } - using JSWrapperObject::internalValue; - - struct Cache; - mutable Cache* m_cache; + mutable RefPtr<DateInstanceData> m_data; }; DateInstance* asDateInstance(JSValue); diff --git a/JavaScriptCore/runtime/DateInstanceCache.h b/JavaScriptCore/runtime/DateInstanceCache.h new file mode 100644 index 0000000..d208580 --- /dev/null +++ b/JavaScriptCore/runtime/DateInstanceCache.h @@ -0,0 +1,94 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DateInstanceCache_h +#define DateInstanceCache_h + +#include <wtf/DateMath.h> +#include <wtf/HashFunctions.h> +#include <wtf/PassRefPtr.h> +#include <wtf/RefCounted.h> + +namespace JSC { + + extern const double NaN; + + class DateInstanceData : public RefCounted<DateInstanceData> { + public: + static PassRefPtr<DateInstanceData> create() { return adoptRef(new DateInstanceData); } + + double m_gregorianDateTimeCachedForMS; + GregorianDateTime m_cachedGregorianDateTime; + double m_gregorianDateTimeUTCCachedForMS; + GregorianDateTime m_cachedGregorianDateTimeUTC; + + private: + DateInstanceData() + : m_gregorianDateTimeCachedForMS(NaN) + , m_gregorianDateTimeUTCCachedForMS(NaN) + { + } + }; + + class DateInstanceCache { + public: + DateInstanceCache() + { + reset(); + } + + void reset() + { + for (size_t i = 0; i < cacheSize; ++i) + m_cache[i].key = NaN; + } + + DateInstanceData* add(double d) + { + CacheEntry& entry = lookup(d); + if (d == entry.key) + return entry.value.get(); + + entry.key = d; + entry.value = DateInstanceData::create(); + return entry.value.get(); + } + + private: + static const size_t cacheSize = 16; + + struct CacheEntry { + double key; + RefPtr<DateInstanceData> value; + }; + + CacheEntry& lookup(double d) { return m_cache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; } + + CacheEntry m_cache[cacheSize]; + }; + +} // namespace JSC + +#endif // DateInstanceCache_h diff --git a/JavaScriptCore/runtime/DatePrototype.cpp b/JavaScriptCore/runtime/DatePrototype.cpp index e2482f4..7a2e802 100644 --- a/JavaScriptCore/runtime/DatePrototype.cpp +++ b/JavaScriptCore/runtime/DatePrototype.cpp @@ -28,7 +28,6 @@ #include "JSString.h" #include "ObjectPrototype.h" #include "DateInstance.h" -#include <float.h> #if !PLATFORM(MAC) && HAVE(LANGINFO_H) #include <langinfo.h> @@ -198,8 +197,8 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L { #if HAVE(LANGINFO_H) static const nl_item formats[] = { D_T_FMT, D_FMT, T_FMT }; -#elif PLATFORM(WINCE) && !PLATFORM(QT) - // strftime() we are using does not support # +#elif (PLATFORM(WINCE) && !PLATFORM(QT)) || PLATFORM(SYMBIAN) + // strftime() does not support '#' on WinCE or Symbian static const char* const formatStrings[] = { "%c", "%x", "%X" }; #else static const char* const formatStrings[] = { "%#c", "%#x", "%X" }; @@ -251,12 +250,12 @@ static JSCell* formatLocaleDate(ExecState* exec, const GregorianDateTime& gdt, L return jsNontrivialString(exec, timebuffer); } -static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double timeInMilliseconds, LocaleDateTimeFormat format, const ArgList&) +static JSCell* formatLocaleDate(ExecState* exec, DateInstance* dateObject, double, LocaleDateTimeFormat format, const ArgList&) { - GregorianDateTime gregorianDateTime; - const bool notUTC = false; - dateObject->msToGregorianDateTime(timeInMilliseconds, notUTC, gregorianDateTime); - return formatLocaleDate(exec, gregorianDateTime, format); + const GregorianDateTime* gregorianDateTime = dateObject->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + return formatLocaleDate(exec, *gregorianDateTime, format); } #endif // !PLATFORM(MAC) @@ -395,10 +394,9 @@ const ClassInfo DatePrototype::info = {"Date", &DateInstance::info, 0, ExecState // ECMA 15.9.4 -DatePrototype::DatePrototype(ExecState* exec, PassRefPtr<Structure> structure) - : DateInstance(structure) +DatePrototype::DatePrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure) + : DateInstance(exec, structure) { - setInternalValue(jsNaN(exec)); // The constructor will be added later, after DateConstructor has been built. } @@ -407,408 +405,317 @@ bool DatePrototype::getOwnPropertySlot(ExecState* exec, const Identifier& proper return getStaticFunctionSlot<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, slot); } + +bool DatePrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticFunctionDescriptor<JSObject>(exec, ExecState::dateTable(exec), this, propertyName, descriptor); +} + // Functions JSValue JSC_HOST_CALL dateProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatDate(t) + " " + formatTime(t, utc)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + return jsNontrivialString(exec, formatDate(*gregorianDateTime) + " " + formatTime(*gregorianDateTime)); } JSValue JSC_HOST_CALL dateProtoFuncToUTCString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + return jsNontrivialString(exec, formatDateUTCVariant(*gregorianDateTime) + " " + formatTimeUTC(*gregorianDateTime)); } JSValue JSC_HOST_CALL dateProtoFuncToISOString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (!isfinite(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - // Maximum amount of space we need in buffer: 6 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) - // 6 for formatting and one for null termination = 23. We add one extra character to allow us to force null termination. - char buffer[24]; - snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02dZ", 1900 + t.year, t.month + 1, t.monthDay, t.hour, t.minute, t.second); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + // Maximum amount of space we need in buffer: 6 (max. digits in year) + 2 * 5 (2 characters each for month, day, hour, minute, second) + 4 (. + 3 digits for milliseconds) + // 6 for formatting and one for null termination = 27. We add one extra character to allow us to force null termination. + char buffer[28]; + snprintf(buffer, sizeof(buffer) - 1, "%04d-%02d-%02dT%02d:%02d:%02d.%03dZ", 1900 + gregorianDateTime->year, gregorianDateTime->month + 1, gregorianDateTime->monthDay, gregorianDateTime->hour, gregorianDateTime->minute, gregorianDateTime->second, static_cast<int>(fmod(thisDateObj->internalNumber(), 1000))); buffer[sizeof(buffer) - 1] = 0; return jsNontrivialString(exec, buffer); } JSValue JSC_HOST_CALL dateProtoFuncToDateString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatDate(t)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + return jsNontrivialString(exec, formatDate(*gregorianDateTime)); } JSValue JSC_HOST_CALL dateProtoFuncToTimeString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatTime(t, utc)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + return jsNontrivialString(exec, formatTime(*gregorianDateTime)); } JSValue JSC_HOST_CALL dateProtoFuncToLocaleString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - - return formatLocaleDate(exec, thisDateObj, milli, LocaleDateAndTime, args); + return formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDateAndTime, args); } JSValue JSC_HOST_CALL dateProtoFuncToLocaleDateString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - - return formatLocaleDate(exec, thisDateObj, milli, LocaleDate, args); + return formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleDate, args); } JSValue JSC_HOST_CALL dateProtoFuncToLocaleTimeString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - - return formatLocaleDate(exec, thisDateObj, milli, LocaleTime, args); + return formatLocaleDate(exec, thisDateObj, thisDateObj->internalNumber(), LocaleTime, args); } JSValue JSC_HOST_CALL dateProtoFuncGetTime(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - - return jsNumber(exec, milli); + return asDateInstance(thisValue)->internalValue(); } JSValue JSC_HOST_CALL dateProtoFuncGetFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, 1900 + t.year); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, 1900 + gregorianDateTime->year); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCFullYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, 1900 + t.year); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, 1900 + gregorianDateTime->year); } JSValue JSC_HOST_CALL dateProtoFuncToGMTString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNontrivialString(exec, "Invalid Date"); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNontrivialString(exec, formatDateUTCVariant(t) + " " + formatTime(t, utc)); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNontrivialString(exec, "Invalid Date"); + return jsNontrivialString(exec, formatDateUTCVariant(*gregorianDateTime) + " " + formatTimeUTC(*gregorianDateTime)); } JSValue JSC_HOST_CALL dateProtoFuncGetMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.month); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->month); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCMonth(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.month); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->month); } JSValue JSC_HOST_CALL dateProtoFuncGetDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.monthDay); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->monthDay); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCDate(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.monthDay); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->monthDay); } JSValue JSC_HOST_CALL dateProtoFuncGetDay(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.weekDay); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->weekDay); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCDay(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.weekDay); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->weekDay); } JSValue JSC_HOST_CALL dateProtoFuncGetHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.hour); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->hour); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCHours(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.hour); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->hour); } JSValue JSC_HOST_CALL dateProtoFuncGetMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.minute); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->minute); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCMinutes(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.minute); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->minute); } JSValue JSC_HOST_CALL dateProtoFuncGetSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.second); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->second); } JSValue JSC_HOST_CALL dateProtoFuncGetUTCSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = true; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, t.second); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTimeUTC(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, gregorianDateTime->second); } JSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -823,7 +730,7 @@ JSValue JSC_HOST_CALL dateProtoFuncGetMilliSeconds(ExecState* exec, JSObject*, J JSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -838,24 +745,20 @@ JSValue JSC_HOST_CALL dateProtoFuncGetUTCMilliseconds(ExecState* exec, JSObject* JSValue JSC_HOST_CALL dateProtoFuncGetTimezoneOffset(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); - return jsNumber(exec, -gmtoffset(t) / minutesPerHour); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); + return jsNumber(exec, -gregorianDateTime->utcOffset / minutesPerHour); } JSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -868,7 +771,7 @@ JSValue JSC_HOST_CALL dateProtoFuncSetTime(ExecState* exec, JSObject*, JSValue t static JSValue setNewValueFromTimeArgs(ExecState* exec, JSValue thisValue, const ArgList& args, int numArgsToUse, bool inputIsUTC) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -883,23 +786,28 @@ static JSValue setNewValueFromTimeArgs(ExecState* exec, JSValue thisValue, const double secs = floor(milli / msPerSecond); double ms = milli - secs * msPerSecond; - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, inputIsUTC, t); + const GregorianDateTime* other = inputIsUTC + ? thisDateObj->gregorianDateTimeUTC(exec) + : thisDateObj->gregorianDateTime(exec); + if (!other) + return jsNaN(exec); - if (!fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &t)) { + GregorianDateTime gregorianDateTime; + gregorianDateTime.copyFrom(*other); + if (!fillStructuresUsingTimeArgs(exec, args, numArgsToUse, &ms, &gregorianDateTime)) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } - JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, inputIsUTC)); + JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC)); thisDateObj->setInternalValue(result); return result; } static JSValue setNewValueFromDateArgs(ExecState* exec, JSValue thisValue, const ArgList& args, int numArgsToUse, bool inputIsUTC) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); DateInstance* thisDateObj = asDateInstance(thisValue); @@ -910,26 +818,28 @@ static JSValue setNewValueFromDateArgs(ExecState* exec, JSValue thisValue, const } double milli = thisDateObj->internalNumber(); - double ms = 0; - - GregorianDateTime t; - if (numArgsToUse == 3 && isnan(milli)) - // Based on ECMA 262 15.9.5.40 - .41 (set[UTC]FullYear) - // the time must be reset to +0 if it is NaN. - thisDateObj->msToGregorianDateTime(0, true, t); - else { - double secs = floor(milli / msPerSecond); - ms = milli - secs * msPerSecond; - thisDateObj->msToGregorianDateTime(milli, inputIsUTC, t); + double ms = 0; + + GregorianDateTime gregorianDateTime; + if (numArgsToUse == 3 && isnan(milli)) + msToGregorianDateTime(exec, 0, true, gregorianDateTime); + else { + ms = milli - floor(milli / msPerSecond) * msPerSecond; + const GregorianDateTime* other = inputIsUTC + ? thisDateObj->gregorianDateTimeUTC(exec) + : thisDateObj->gregorianDateTime(exec); + if (!other) + return jsNaN(exec); + gregorianDateTime.copyFrom(*other); } - if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &t)) { + if (!fillStructuresUsingDateArgs(exec, args, numArgsToUse, &ms, &gregorianDateTime)) { JSValue result = jsNaN(exec); thisDateObj->setInternalValue(result); return result; } - JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, inputIsUTC)); + JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, inputIsUTC)); thisDateObj->setInternalValue(result); return result; } @@ -1020,11 +930,9 @@ JSValue JSC_HOST_CALL dateProtoFuncSetUTCFullYear(ExecState* exec, JSObject*, JS JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); if (args.isEmpty()) { JSValue result = jsNaN(exec); @@ -1035,15 +943,16 @@ JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec, JSObject*, JSValue t double milli = thisDateObj->internalNumber(); double ms = 0; - GregorianDateTime t; + GregorianDateTime gregorianDateTime; if (isnan(milli)) // Based on ECMA 262 B.2.5 (setYear) // the time must be reset to +0 if it is NaN. - thisDateObj->msToGregorianDateTime(0, true, t); + msToGregorianDateTime(exec, 0, true, gregorianDateTime); else { double secs = floor(milli / msPerSecond); ms = milli - secs * msPerSecond; - thisDateObj->msToGregorianDateTime(milli, utc, t); + if (const GregorianDateTime* other = thisDateObj->gregorianDateTime(exec)) + gregorianDateTime.copyFrom(*other); } bool ok = true; @@ -1054,29 +963,25 @@ JSValue JSC_HOST_CALL dateProtoFuncSetYear(ExecState* exec, JSObject*, JSValue t return result; } - t.year = (year > 99 || year < 0) ? year - 1900 : year; - JSValue result = jsNumber(exec, gregorianDateTimeToMS(t, ms, utc)); + gregorianDateTime.year = (year > 99 || year < 0) ? year - 1900 : year; + JSValue result = jsNumber(exec, gregorianDateTimeToMS(exec, gregorianDateTime, ms, false)); thisDateObj->setInternalValue(result); return result; } JSValue JSC_HOST_CALL dateProtoFuncGetYear(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&DateInstance::info)) + if (!thisValue.inherits(&DateInstance::info)) return throwError(exec, TypeError); - const bool utc = false; - DateInstance* thisDateObj = asDateInstance(thisValue); - double milli = thisDateObj->internalNumber(); - if (isnan(milli)) - return jsNaN(exec); - GregorianDateTime t; - thisDateObj->msToGregorianDateTime(milli, utc, t); + const GregorianDateTime* gregorianDateTime = thisDateObj->gregorianDateTime(exec); + if (!gregorianDateTime) + return jsNaN(exec); // NOTE: IE returns the full year even in getYear. - return jsNumber(exec, t.year); + return jsNumber(exec, gregorianDateTime->year); } JSValue JSC_HOST_CALL dateProtoFuncToJSON(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) diff --git a/JavaScriptCore/runtime/DatePrototype.h b/JavaScriptCore/runtime/DatePrototype.h index 5f4d0ec..f565775 100644 --- a/JavaScriptCore/runtime/DatePrototype.h +++ b/JavaScriptCore/runtime/DatePrototype.h @@ -29,17 +29,22 @@ namespace JSC { class DatePrototype : public DateInstance { public: - DatePrototype(ExecState*, PassRefPtr<Structure>); + DatePrototype(ExecState*, NonNullPassRefPtr<Structure>); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | DateInstance::StructureFlags; + }; } // namespace JSC diff --git a/JavaScriptCore/runtime/Error.cpp b/JavaScriptCore/runtime/Error.cpp index db1d8cc..ddd4bc4 100644 --- a/JavaScriptCore/runtime/Error.cpp +++ b/JavaScriptCore/runtime/Error.cpp @@ -97,6 +97,12 @@ JSObject* Error::create(ExecState* exec, ErrorType type, const char* message) return create(exec, type, message, -1, -1, NULL); } +JSObject* throwError(ExecState* exec, JSObject* error) +{ + exec->setException(error); + return error; +} + JSObject* throwError(ExecState* exec, ErrorType type) { JSObject* error = Error::create(exec, type, UString(), -1, -1, NULL); diff --git a/JavaScriptCore/runtime/Error.h b/JavaScriptCore/runtime/Error.h index adf7fdf..e959cff 100644 --- a/JavaScriptCore/runtime/Error.h +++ b/JavaScriptCore/runtime/Error.h @@ -59,6 +59,7 @@ namespace JSC { JSObject* throwError(ExecState*, ErrorType, const UString& message); JSObject* throwError(ExecState*, ErrorType, const char* message); JSObject* throwError(ExecState*, ErrorType); + JSObject* throwError(ExecState*, JSObject*); } // namespace JSC diff --git a/JavaScriptCore/runtime/ErrorConstructor.cpp b/JavaScriptCore/runtime/ErrorConstructor.cpp index 07b7e23..b9c3f58 100644 --- a/JavaScriptCore/runtime/ErrorConstructor.cpp +++ b/JavaScriptCore/runtime/ErrorConstructor.cpp @@ -29,7 +29,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(ErrorConstructor); -ErrorConstructor::ErrorConstructor(ExecState* exec, PassRefPtr<Structure> structure, ErrorPrototype* errorPrototype) +ErrorConstructor::ErrorConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ErrorPrototype* errorPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, errorPrototype->classInfo()->className)) { // ECMA 15.11.3.1 Error.prototype diff --git a/JavaScriptCore/runtime/ErrorConstructor.h b/JavaScriptCore/runtime/ErrorConstructor.h index 2dd4124..e3d789b 100644 --- a/JavaScriptCore/runtime/ErrorConstructor.h +++ b/JavaScriptCore/runtime/ErrorConstructor.h @@ -30,7 +30,7 @@ namespace JSC { class ErrorConstructor : public InternalFunction { public: - ErrorConstructor(ExecState*, PassRefPtr<Structure>, ErrorPrototype*); + ErrorConstructor(ExecState*, NonNullPassRefPtr<Structure>, ErrorPrototype*); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/JavaScriptCore/runtime/ErrorInstance.cpp b/JavaScriptCore/runtime/ErrorInstance.cpp index 2e2cdce..1cdb87a 100644 --- a/JavaScriptCore/runtime/ErrorInstance.cpp +++ b/JavaScriptCore/runtime/ErrorInstance.cpp @@ -25,7 +25,7 @@ namespace JSC { const ClassInfo ErrorInstance::info = { "Error", 0, 0, 0 }; -ErrorInstance::ErrorInstance(PassRefPtr<Structure> structure) +ErrorInstance::ErrorInstance(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { } diff --git a/JavaScriptCore/runtime/ErrorInstance.h b/JavaScriptCore/runtime/ErrorInstance.h index 6f9d262..9f53b51 100644 --- a/JavaScriptCore/runtime/ErrorInstance.h +++ b/JavaScriptCore/runtime/ErrorInstance.h @@ -27,7 +27,7 @@ namespace JSC { class ErrorInstance : public JSObject { public: - explicit ErrorInstance(PassRefPtr<Structure>); + explicit ErrorInstance(NonNullPassRefPtr<Structure>); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; diff --git a/JavaScriptCore/runtime/ErrorPrototype.cpp b/JavaScriptCore/runtime/ErrorPrototype.cpp index 599390e..a9a7a43 100644 --- a/JavaScriptCore/runtime/ErrorPrototype.cpp +++ b/JavaScriptCore/runtime/ErrorPrototype.cpp @@ -34,7 +34,7 @@ ASSERT_CLASS_FITS_IN_CELL(ErrorPrototype); static JSValue JSC_HOST_CALL errorProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); // ECMA 15.9.4 -ErrorPrototype::ErrorPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) +ErrorPrototype::ErrorPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) : ErrorInstance(structure) { // The constructor will be added later in ErrorConstructor's constructor diff --git a/JavaScriptCore/runtime/ErrorPrototype.h b/JavaScriptCore/runtime/ErrorPrototype.h index 53d12d9..a561590 100644 --- a/JavaScriptCore/runtime/ErrorPrototype.h +++ b/JavaScriptCore/runtime/ErrorPrototype.h @@ -29,7 +29,7 @@ namespace JSC { class ErrorPrototype : public ErrorInstance { public: - ErrorPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + ErrorPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); }; } // namespace JSC diff --git a/JavaScriptCore/runtime/ExceptionHelpers.cpp b/JavaScriptCore/runtime/ExceptionHelpers.cpp index e63594c..5bead90 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.cpp +++ b/JavaScriptCore/runtime/ExceptionHelpers.cpp @@ -66,6 +66,11 @@ JSValue createStackOverflowError(ExecState* exec) return createError(exec, RangeError, "Maximum call stack size exceeded."); } +JSValue createTypeError(ExecState* exec, const char* message) +{ + return createError(exec, TypeError, message); +} + JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, unsigned bytecodeOffset, CodeBlock* codeBlock) { int startOffset = 0; @@ -74,7 +79,7 @@ JSValue createUndefinedVariableError(ExecState* exec, const Identifier& ident, u int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); UString message = "Can't find variable: "; message.append(ident.ustring()); - JSObject* exception = Error::create(exec, ReferenceError, message, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + JSObject* exception = Error::create(exec, ReferenceError, message, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); @@ -136,7 +141,7 @@ JSObject* createInvalidParamError(ExecState* exec, const char* op, JSValue value int divotPoint = 0; int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint, divotPoint + endOffset, value, message); - JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); @@ -157,7 +162,7 @@ JSObject* createNotAConstructorError(ExecState* exec, JSValue value, unsigned by startPoint++; UString errorMessage = createErrorMessage(exec, codeBlock, line, startPoint, divotPoint, value, "not a constructor"); - JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); @@ -171,7 +176,7 @@ JSValue createNotAFunctionError(ExecState* exec, JSValue value, unsigned bytecod int divotPoint = 0; int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, value, "not a function"); - JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); @@ -201,7 +206,7 @@ JSObject* createNotAnObjectError(ExecState* exec, JSNotAnObjectErrorStub* error, int divotPoint = 0; int line = codeBlock->expressionRangeForBytecodeOffset(exec, bytecodeOffset, divotPoint, startOffset, endOffset); UString errorMessage = createErrorMessage(exec, codeBlock, line, divotPoint - startOffset, divotPoint, error->isNull() ? jsNull() : jsUndefined(), "not an object"); - JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerNode()->sourceID(), codeBlock->ownerNode()->sourceURL()); + JSObject* exception = Error::create(exec, TypeError, errorMessage, line, codeBlock->ownerExecutable()->sourceID(), codeBlock->ownerExecutable()->sourceURL()); exception->putWithAttributes(exec, Identifier(exec, expressionBeginOffsetPropertyName), jsNumber(exec, divotPoint - startOffset), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionCaretOffsetPropertyName), jsNumber(exec, divotPoint), ReadOnly | DontDelete); exception->putWithAttributes(exec, Identifier(exec, expressionEndOffsetPropertyName), jsNumber(exec, divotPoint + endOffset), ReadOnly | DontDelete); diff --git a/JavaScriptCore/runtime/ExceptionHelpers.h b/JavaScriptCore/runtime/ExceptionHelpers.h index 4c5bec1..e739d09 100644 --- a/JavaScriptCore/runtime/ExceptionHelpers.h +++ b/JavaScriptCore/runtime/ExceptionHelpers.h @@ -44,6 +44,7 @@ namespace JSC { JSValue createInterruptedExecutionException(JSGlobalData*); JSValue createStackOverflowError(ExecState*); + JSValue createTypeError(ExecState*, const char* message); JSValue createUndefinedVariableError(ExecState*, const Identifier&, unsigned bytecodeOffset, CodeBlock*); JSNotAnObjectErrorStub* createNotAnObjectErrorStub(ExecState*, bool isNull); JSObject* createInvalidParamError(ExecState*, const char* op, JSValue, unsigned bytecodeOffset, CodeBlock*); diff --git a/JavaScriptCore/runtime/Executable.cpp b/JavaScriptCore/runtime/Executable.cpp new file mode 100644 index 0000000..7586746 --- /dev/null +++ b/JavaScriptCore/runtime/Executable.cpp @@ -0,0 +1,280 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "Executable.h" + +#include "BytecodeGenerator.h" +#include "CodeBlock.h" +#include "JIT.h" +#include "Parser.h" +#include "Vector.h" + +namespace JSC { + +#if ENABLE(JIT) +NativeExecutable::~NativeExecutable() +{ +} +#endif + +VPtrHackExecutable::~VPtrHackExecutable() +{ +} + +EvalExecutable::~EvalExecutable() +{ + delete m_evalCodeBlock; +} + +ProgramExecutable::~ProgramExecutable() +{ + delete m_programCodeBlock; +} + +FunctionExecutable::~FunctionExecutable() +{ + delete m_codeBlock; +} + +JSObject* EvalExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + int errLine; + UString errMsg; + RefPtr<EvalNode> evalNode = exec->globalData().parser->parse<EvalNode>(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); + if (!evalNode) + return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); + recordParse(evalNode->features(), evalNode->lineNo(), evalNode->lastLine()); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + ASSERT(!m_evalCodeBlock); + m_evalCodeBlock = new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth()); + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(evalNode.get(), globalObject->debugger(), scopeChain, m_evalCodeBlock->symbolTable(), m_evalCodeBlock)); + generator->generate(); + + evalNode->destroyData(); + return 0; +} + +JSObject* ProgramExecutable::checkSyntax(ExecState* exec) +{ + int errLine; + UString errMsg; + RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); + if (!programNode) + return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); + return 0; +} + +JSObject* ProgramExecutable::compile(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + int errLine; + UString errMsg; + RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), exec->lexicalGlobalObject()->debugger(), exec, m_source, &errLine, &errMsg); + if (!programNode) + return Error::create(exec, SyntaxError, errMsg, errLine, m_source.provider()->asID(), m_source.provider()->url()); + recordParse(programNode->features(), programNode->lineNo(), programNode->lastLine()); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + ASSERT(!m_programCodeBlock); + m_programCodeBlock = new ProgramCodeBlock(this, GlobalCode, globalObject, source().provider()); + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(programNode.get(), globalObject->debugger(), scopeChain, &globalObject->symbolTable(), m_programCodeBlock)); + generator->generate(); + + programNode->destroyData(); + return 0; +} + +void FunctionExecutable::compile(ExecState*, ScopeChainNode* scopeChainNode) +{ + JSGlobalData* globalData = scopeChainNode->globalData; + RefPtr<FunctionBodyNode> body = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source); + if (m_forceUsesArguments) + body->setUsesArguments(); + body->finishParsing(m_parameters, m_name); + recordParse(body->features(), body->lineNo(), body->lastLine()); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + ASSERT(!m_codeBlock); + m_codeBlock = new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset()); + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(body.get(), globalObject->debugger(), scopeChain, m_codeBlock->symbolTable(), m_codeBlock)); + generator->generate(); + m_numParameters = m_codeBlock->m_numParameters; + ASSERT(m_numParameters); + m_numVariables = m_codeBlock->m_numVars; + + body->destroyData(); +} + +#if ENABLE(JIT) + +void EvalExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); + m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + codeBlock->discardBytecode(); +#endif +} + +void ProgramExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); + m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + codeBlock->discardBytecode(); +#endif +} + +void FunctionExecutable::generateJITCode(ExecState* exec, ScopeChainNode* scopeChainNode) +{ + CodeBlock* codeBlock = &bytecode(exec, scopeChainNode); + m_jitCode = JIT::compile(scopeChainNode->globalData, codeBlock); + +#if !ENABLE(OPCODE_SAMPLING) + if (!BytecodeGenerator::dumpsGeneratedCode()) + codeBlock->discardBytecode(); +#endif +} + +#endif + +void FunctionExecutable::markAggregate(MarkStack& markStack) +{ + if (m_codeBlock) + m_codeBlock->markAggregate(markStack); +} + +ExceptionInfo* FunctionExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) +{ + RefPtr<FunctionBodyNode> newFunctionBody = globalData->parser->parse<FunctionBodyNode>(globalData, 0, 0, m_source); + if (m_forceUsesArguments) + newFunctionBody->setUsesArguments(); + newFunctionBody->finishParsing(m_parameters, m_name); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + OwnPtr<CodeBlock> newCodeBlock(new FunctionCodeBlock(this, FunctionCode, source().provider(), source().startOffset())); + globalData->functionCodeBlockBeingReparsed = newCodeBlock.get(); + + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(newFunctionBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); + generator->setRegeneratingForExceptionInfo(static_cast<FunctionCodeBlock*>(codeBlock)); + generator->generate(); + + ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); + +#if ENABLE(JIT) + JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); + ASSERT(newJITCode.size() == generatedJITCode().size()); +#endif + + globalData->functionCodeBlockBeingReparsed = 0; + + return newCodeBlock->extractExceptionInfo(); +} + +ExceptionInfo* EvalExecutable::reparseExceptionInfo(JSGlobalData* globalData, ScopeChainNode* scopeChainNode, CodeBlock* codeBlock) +{ + RefPtr<EvalNode> newEvalBody = globalData->parser->parse<EvalNode>(globalData, 0, 0, m_source); + + ScopeChain scopeChain(scopeChainNode); + JSGlobalObject* globalObject = scopeChain.globalObject(); + + OwnPtr<EvalCodeBlock> newCodeBlock(new EvalCodeBlock(this, globalObject, source().provider(), scopeChain.localDepth())); + + OwnPtr<BytecodeGenerator> generator(new BytecodeGenerator(newEvalBody.get(), globalObject->debugger(), scopeChain, newCodeBlock->symbolTable(), newCodeBlock.get())); + generator->setRegeneratingForExceptionInfo(static_cast<EvalCodeBlock*>(codeBlock)); + generator->generate(); + + ASSERT(newCodeBlock->instructionCount() == codeBlock->instructionCount()); + +#if ENABLE(JIT) + JITCode newJITCode = JIT::compile(globalData, newCodeBlock.get()); + ASSERT(newJITCode.size() == generatedJITCode().size()); +#endif + + return newCodeBlock->extractExceptionInfo(); +} + +void FunctionExecutable::recompile(ExecState*) +{ + delete m_codeBlock; + m_codeBlock = 0; + m_numParameters = NUM_PARAMETERS_NOT_COMPILED; +#if ENABLE(JIT) + m_jitCode = JITCode(); +#endif +} + +PassRefPtr<FunctionExecutable> FunctionExecutable::fromGlobalCode(const Identifier& functionName, ExecState* exec, Debugger* debugger, const SourceCode& source, int* errLine, UString* errMsg) +{ + RefPtr<ProgramNode> program = exec->globalData().parser->parse<ProgramNode>(&exec->globalData(), debugger, exec, source, errLine, errMsg); + if (!program) + return 0; + + StatementNode* exprStatement = program->singleStatement(); + ASSERT(exprStatement); + ASSERT(exprStatement->isExprStatement()); + if (!exprStatement || !exprStatement->isExprStatement()) + return 0; + + ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); + ASSERT(funcExpr); + ASSERT(funcExpr->isFuncExprNode()); + if (!funcExpr || !funcExpr->isFuncExprNode()) + return 0; + + FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); + ASSERT(body); + return FunctionExecutable::create(&exec->globalData(), functionName, body->source(), body->usesArguments(), body->parameters(), body->lineNo(), body->lastLine()); +} + +UString FunctionExecutable::paramString() const +{ + FunctionParameters& parameters = *m_parameters; + UString s(""); + for (size_t pos = 0; pos < parameters.size(); ++pos) { + if (!s.isEmpty()) + s += ", "; + s += parameters[pos].ustring(); + } + + return s; +} + +}; + + diff --git a/JavaScriptCore/runtime/Executable.h b/JavaScriptCore/runtime/Executable.h new file mode 100644 index 0000000..f74abe9 --- /dev/null +++ b/JavaScriptCore/runtime/Executable.h @@ -0,0 +1,356 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef Executable_h +#define Executable_h + +#include "JSFunction.h" +#include "Interpreter.h" +#include "Nodes.h" +#include "SamplingTool.h" + +namespace JSC { + + class CodeBlock; + class Debugger; + class EvalCodeBlock; + class ProgramCodeBlock; + class ScopeChainNode; + + struct ExceptionInfo; + + class ExecutableBase : public RefCounted<ExecutableBase> { + friend class JIT; + + protected: + static const int NUM_PARAMETERS_IS_HOST = 0; + static const int NUM_PARAMETERS_NOT_COMPILED = -1; + + public: + ExecutableBase(int numParameters) + : m_numParameters(numParameters) + { + } + + virtual ~ExecutableBase() {} + + bool isHostFunction() const { return m_numParameters == NUM_PARAMETERS_IS_HOST; } + + protected: + int m_numParameters; + +#if ENABLE(JIT) + public: + JITCode& generatedJITCode() + { + ASSERT(m_jitCode); + return m_jitCode; + } + + ExecutablePool* getExecutablePool() + { + return m_jitCode.getExecutablePool(); + } + + protected: + JITCode m_jitCode; +#endif + }; + +#if ENABLE(JIT) + class NativeExecutable : public ExecutableBase { + public: + NativeExecutable(ExecState* exec) + : ExecutableBase(NUM_PARAMETERS_IS_HOST) + { + m_jitCode = JITCode(JITCode::HostFunction(exec->globalData().jitStubs.ctiNativeCallThunk())); + } + + ~NativeExecutable(); + }; +#endif + + class VPtrHackExecutable : public ExecutableBase { + public: + VPtrHackExecutable() + : ExecutableBase(NUM_PARAMETERS_IS_HOST) + { + } + + ~VPtrHackExecutable(); + }; + + class ScriptExecutable : public ExecutableBase { + public: + ScriptExecutable(JSGlobalData* globalData, const SourceCode& source) + : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) + , m_source(source) + , m_features(0) + { +#if ENABLE(CODEBLOCK_SAMPLING) + if (SamplingTool* sampler = globalData->interpreter->sampler()) + sampler->notifyOfScope(this); +#else + UNUSED_PARAM(globalData); +#endif + } + + ScriptExecutable(ExecState* exec, const SourceCode& source) + : ExecutableBase(NUM_PARAMETERS_NOT_COMPILED) + , m_source(source) + , m_features(0) + { +#if ENABLE(CODEBLOCK_SAMPLING) + if (SamplingTool* sampler = exec->globalData().interpreter->sampler()) + sampler->notifyOfScope(this); +#else + UNUSED_PARAM(exec); +#endif + } + + const SourceCode& source() { return m_source; } + intptr_t sourceID() const { return m_source.provider()->asID(); } + const UString& sourceURL() const { return m_source.provider()->url(); } + int lineNo() const { return m_firstLine; } + int lastLine() const { return m_lastLine; } + + bool usesEval() const { return m_features & EvalFeature; } + bool usesArguments() const { return m_features & ArgumentsFeature; } + bool needsActivation() const { return m_features & (EvalFeature | ClosureFeature | WithFeature | CatchFeature); } + + virtual ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) = 0; + + protected: + void recordParse(CodeFeatures features, int firstLine, int lastLine) + { + m_features = features; + m_firstLine = firstLine; + m_lastLine = lastLine; + } + + SourceCode m_source; + CodeFeatures m_features; + int m_firstLine; + int m_lastLine; + }; + + class EvalExecutable : public ScriptExecutable { + public: + + ~EvalExecutable(); + + EvalCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) + { + if (!m_evalCodeBlock) { + JSObject* error = compile(exec, scopeChainNode); + ASSERT_UNUSED(!error, error); + } + return *m_evalCodeBlock; + } + + JSObject* compile(ExecState*, ScopeChainNode*); + + ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); + static PassRefPtr<EvalExecutable> create(ExecState* exec, const SourceCode& source) { return adoptRef(new EvalExecutable(exec, source)); } + + private: + EvalExecutable(ExecState* exec, const SourceCode& source) + : ScriptExecutable(exec, source) + , m_evalCodeBlock(0) + { + } + EvalCodeBlock* m_evalCodeBlock; + +#if ENABLE(JIT) + public: + JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) + { + if (!m_jitCode) + generateJITCode(exec, scopeChainNode); + return m_jitCode; + } + + private: + void generateJITCode(ExecState*, ScopeChainNode*); +#endif + }; + + class ProgramExecutable : public ScriptExecutable { + public: + static PassRefPtr<ProgramExecutable> create(ExecState* exec, const SourceCode& source) + { + return adoptRef(new ProgramExecutable(exec, source)); + } + + ~ProgramExecutable(); + + ProgramCodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) + { + if (!m_programCodeBlock) { + JSObject* error = compile(exec, scopeChainNode); + ASSERT_UNUSED(!error, error); + } + return *m_programCodeBlock; + } + + JSObject* checkSyntax(ExecState*); + JSObject* compile(ExecState*, ScopeChainNode*); + + // CodeBlocks for program code are transient and therefore do not gain from from throwing out there exception information. + ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*) { ASSERT_NOT_REACHED(); return 0; } + + private: + ProgramExecutable(ExecState* exec, const SourceCode& source) + : ScriptExecutable(exec, source) + , m_programCodeBlock(0) + { + } + ProgramCodeBlock* m_programCodeBlock; + +#if ENABLE(JIT) + public: + JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) + { + if (!m_jitCode) + generateJITCode(exec, scopeChainNode); + return m_jitCode; + } + + private: + void generateJITCode(ExecState*, ScopeChainNode*); +#endif + }; + + class FunctionExecutable : public ScriptExecutable { + friend class JIT; + public: + static PassRefPtr<FunctionExecutable> create(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) + { + return adoptRef(new FunctionExecutable(exec, name, source, forceUsesArguments, parameters, firstLine, lastLine)); + } + + static PassRefPtr<FunctionExecutable> create(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) + { + return adoptRef(new FunctionExecutable(globalData, name, source, forceUsesArguments, parameters, firstLine, lastLine)); + } + + ~FunctionExecutable(); + + JSFunction* make(ExecState* exec, ScopeChainNode* scopeChain) + { + return new (exec) JSFunction(exec, this, scopeChain); + } + + CodeBlock& bytecode(ExecState* exec, ScopeChainNode* scopeChainNode) + { + ASSERT(scopeChainNode); + if (!m_codeBlock) + compile(exec, scopeChainNode); + return *m_codeBlock; + } + + bool isGenerated() const + { + return m_codeBlock; + } + + CodeBlock& generatedBytecode() + { + ASSERT(m_codeBlock); + return *m_codeBlock; + } + + const Identifier& name() { return m_name; } + size_t parameterCount() const { return m_parameters->size(); } + size_t variableCount() const { return m_numVariables; } + UString paramString() const; + + void recompile(ExecState*); + ExceptionInfo* reparseExceptionInfo(JSGlobalData*, ScopeChainNode*, CodeBlock*); + void markAggregate(MarkStack& markStack); + static PassRefPtr<FunctionExecutable> fromGlobalCode(const Identifier&, ExecState*, Debugger*, const SourceCode&, int* errLine = 0, UString* errMsg = 0); + + private: + FunctionExecutable(JSGlobalData* globalData, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) + : ScriptExecutable(globalData, source) + , m_forceUsesArguments(forceUsesArguments) + , m_parameters(parameters) + , m_codeBlock(0) + , m_name(name) + , m_numVariables(0) + { + m_firstLine = firstLine; + m_lastLine = lastLine; + } + + FunctionExecutable(ExecState* exec, const Identifier& name, const SourceCode& source, bool forceUsesArguments, FunctionParameters* parameters, int firstLine, int lastLine) + : ScriptExecutable(exec, source) + , m_forceUsesArguments(forceUsesArguments) + , m_parameters(parameters) + , m_codeBlock(0) + , m_name(name) + , m_numVariables(0) + { + m_firstLine = firstLine; + m_lastLine = lastLine; + } + + void compile(ExecState*, ScopeChainNode*); + + bool m_forceUsesArguments; + RefPtr<FunctionParameters> m_parameters; + CodeBlock* m_codeBlock; + Identifier m_name; + size_t m_numVariables; + +#if ENABLE(JIT) + public: + JITCode& jitCode(ExecState* exec, ScopeChainNode* scopeChainNode) + { + if (!m_jitCode) + generateJITCode(exec, scopeChainNode); + return m_jitCode; + } + + private: + void generateJITCode(ExecState*, ScopeChainNode*); +#endif + }; + + inline FunctionExecutable* JSFunction::jsExecutable() const + { + ASSERT(!isHostFunctionNonInline()); + return static_cast<FunctionExecutable*>(m_executable.get()); + } + + inline bool JSFunction::isHostFunction() const + { + ASSERT(m_executable); + return m_executable->isHostFunction(); + } + +} + +#endif diff --git a/JavaScriptCore/runtime/FunctionConstructor.cpp b/JavaScriptCore/runtime/FunctionConstructor.cpp index f4f5cc8..9d88400 100644 --- a/JavaScriptCore/runtime/FunctionConstructor.cpp +++ b/JavaScriptCore/runtime/FunctionConstructor.cpp @@ -34,7 +34,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(FunctionConstructor); -FunctionConstructor::FunctionConstructor(ExecState* exec, PassRefPtr<Structure> structure, FunctionPrototype* functionPrototype) +FunctionConstructor::FunctionConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, FunctionPrototype* functionPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, functionPrototype->classInfo()->className)) { putDirectWithoutTransition(exec->propertyNames().prototype, functionPrototype, DontEnum | DontDelete | ReadOnly); @@ -66,32 +66,6 @@ CallType FunctionConstructor::getCallData(CallData& callData) return CallTypeHost; } -FunctionBodyNode* extractFunctionBody(ProgramNode* program) -{ - if (!program) - return 0; - - StatementVector& children = program->children(); - if (children.size() != 1) - return 0; - - StatementNode* exprStatement = children[0]; - ASSERT(exprStatement); - ASSERT(exprStatement->isExprStatement()); - if (!exprStatement || !exprStatement->isExprStatement()) - return 0; - - ExpressionNode* funcExpr = static_cast<ExprStatementNode*>(exprStatement)->expr(); - ASSERT(funcExpr); - ASSERT(funcExpr->isFuncExprNode()); - if (!funcExpr || !funcExpr->isFuncExprNode()) - return 0; - - FunctionBodyNode* body = static_cast<FuncExprNode*>(funcExpr)->body(); - ASSERT(body); - return body; -} - // ECMA 15.3.2 The Function Constructor JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifier& functionName, const UString& sourceURL, int lineNumber) { @@ -113,15 +87,13 @@ JSObject* constructFunction(ExecState* exec, const ArgList& args, const Identifi int errLine; UString errMsg; SourceCode source = makeSource(program, sourceURL, lineNumber); - RefPtr<ProgramNode> programNode = exec->globalData().parser->parse<ProgramNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); - - FunctionBodyNode* body = extractFunctionBody(programNode.get()); - if (!body) + RefPtr<FunctionExecutable> function = FunctionExecutable::fromGlobalCode(functionName, exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); + if (!function) return throwError(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), source.provider()->url()); JSGlobalObject* globalObject = exec->lexicalGlobalObject(); - ScopeChain scopeChain(globalObject, globalObject->globalData(), exec->globalThisValue()); - return new (exec) JSFunction(exec, functionName, body, scopeChain.node()); + ScopeChain scopeChain(globalObject, globalObject->globalData(), globalObject, exec->globalThisValue()); + return new (exec) JSFunction(exec, function, scopeChain.node()); } // ECMA 15.3.2 The Function Constructor diff --git a/JavaScriptCore/runtime/FunctionConstructor.h b/JavaScriptCore/runtime/FunctionConstructor.h index 124b354..197f320 100644 --- a/JavaScriptCore/runtime/FunctionConstructor.h +++ b/JavaScriptCore/runtime/FunctionConstructor.h @@ -26,12 +26,10 @@ namespace JSC { class FunctionPrototype; - class ProgramNode; - class FunctionBodyNode; class FunctionConstructor : public InternalFunction { public: - FunctionConstructor(ExecState*, PassRefPtr<Structure>, FunctionPrototype*); + FunctionConstructor(ExecState*, NonNullPassRefPtr<Structure>, FunctionPrototype*); private: virtual ConstructType getConstructData(ConstructData&); @@ -41,8 +39,6 @@ namespace JSC { JSObject* constructFunction(ExecState*, const ArgList&, const Identifier& functionName, const UString& sourceURL, int lineNumber); JSObject* constructFunction(ExecState*, const ArgList&); - FunctionBodyNode* extractFunctionBody(ProgramNode*); - } // namespace JSC #endif // FunctionConstructor_h diff --git a/JavaScriptCore/runtime/FunctionPrototype.cpp b/JavaScriptCore/runtime/FunctionPrototype.cpp index 9ba2144..a3a7479 100644 --- a/JavaScriptCore/runtime/FunctionPrototype.cpp +++ b/JavaScriptCore/runtime/FunctionPrototype.cpp @@ -1,6 +1,6 @@ /* * Copyright (C) 1999-2001 Harri Porten (porten@kde.org) - * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. + * Copyright (C) 2003, 2004, 2005, 2006, 2007, 2008, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public @@ -37,7 +37,7 @@ static JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState*, JSObject*, JS static JSValue JSC_HOST_CALL functionProtoFuncApply(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL functionProtoFuncCall(ExecState*, JSObject*, JSValue, const ArgList&); -FunctionPrototype::FunctionPrototype(ExecState* exec, PassRefPtr<Structure> structure) +FunctionPrototype::FunctionPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure) : InternalFunction(&exec->globalData(), structure, exec->propertyNames().nullIdentifier) { putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 0), DontDelete | ReadOnly | DontEnum); @@ -84,18 +84,19 @@ static inline void insertSemicolonIfNeeded(UString& functionBody) JSValue JSC_HOST_CALL functionProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (thisValue.isObject(&JSFunction::info)) { + if (thisValue.inherits(&JSFunction::info)) { JSFunction* function = asFunction(thisValue); if (!function->isHostFunction()) { - UString functionBody = function->body()->toSourceString(); - insertSemicolonIfNeeded(functionBody); - return jsString(exec, "function " + function->name(&exec->globalData()) + "(" + function->body()->paramString() + ") " + functionBody); + FunctionExecutable* executable = function->jsExecutable(); + UString sourceString = executable->source().toString(); + insertSemicolonIfNeeded(sourceString); + return jsString(exec, "function " + function->name(exec) + "(" + executable->paramString() + ") " + sourceString); } } - if (thisValue.isObject(&InternalFunction::info)) { + if (thisValue.inherits(&InternalFunction::info)) { InternalFunction* function = asInternalFunction(thisValue); - return jsString(exec, "function " + function->name(&exec->globalData()) + "() {\n [native code]\n}"); + return jsString(exec, "function " + function->name(exec) + "() {\n [native code]\n}"); } return throwError(exec, TypeError); diff --git a/JavaScriptCore/runtime/FunctionPrototype.h b/JavaScriptCore/runtime/FunctionPrototype.h index 607ddab..d1d6a1d 100644 --- a/JavaScriptCore/runtime/FunctionPrototype.h +++ b/JavaScriptCore/runtime/FunctionPrototype.h @@ -29,12 +29,12 @@ namespace JSC { class FunctionPrototype : public InternalFunction { public: - FunctionPrototype(ExecState*, PassRefPtr<Structure>); + FunctionPrototype(ExecState*, NonNullPassRefPtr<Structure>); void addFunctionProperties(ExecState*, Structure* prototypeFunctionStructure, NativeFunctionWrapper** callFunction, NativeFunctionWrapper** applyFunction); static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } private: diff --git a/JavaScriptCore/runtime/GetterSetter.cpp b/JavaScriptCore/runtime/GetterSetter.cpp index cc85354..7e54053 100644 --- a/JavaScriptCore/runtime/GetterSetter.cpp +++ b/JavaScriptCore/runtime/GetterSetter.cpp @@ -32,50 +32,12 @@ void GetterSetter::markChildren(MarkStack& markStack) { JSCell::markChildren(markStack); - if (m_getter && !m_getter->marked()) + if (m_getter) markStack.append(m_getter); - if (m_setter && !m_setter->marked()) + if (m_setter) markStack.append(m_setter); } -JSValue GetterSetter::toPrimitive(ExecState*, PreferredPrimitiveType) const -{ - ASSERT_NOT_REACHED(); - return jsNull(); -} - -bool GetterSetter::getPrimitiveNumber(ExecState*, double& number, JSValue& value) -{ - ASSERT_NOT_REACHED(); - number = 0; - value = JSValue(); - return true; -} - -bool GetterSetter::toBoolean(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return false; -} - -double GetterSetter::toNumber(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return 0.0; -} - -UString GetterSetter::toString(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return UString::null(); -} - -JSObject* GetterSetter::toObject(ExecState* exec) const -{ - ASSERT_NOT_REACHED(); - return jsNull().toObject(exec); -} - bool GetterSetter::isGetterSetter() const { return true; diff --git a/JavaScriptCore/runtime/GetterSetter.h b/JavaScriptCore/runtime/GetterSetter.h index b7a8794..68e9ea3 100644 --- a/JavaScriptCore/runtime/GetterSetter.h +++ b/JavaScriptCore/runtime/GetterSetter.h @@ -50,18 +50,11 @@ namespace JSC { void setSetter(JSObject* setter) { m_setter = setter; } static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(GetterSetterType)); + return Structure::create(prototype, TypeInfo(GetterSetterType, OverridesMarkChildren)); } private: virtual bool isGetterSetter() const; - virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; - virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); - virtual bool toBoolean(ExecState*) const; - virtual double toNumber(ExecState*) const; - virtual UString toString(ExecState*) const; - virtual JSObject* toObject(ExecState*) const; - JSObject* m_getter; JSObject* m_setter; }; diff --git a/JavaScriptCore/runtime/GlobalEvalFunction.cpp b/JavaScriptCore/runtime/GlobalEvalFunction.cpp index 3074f95..c26002b 100644 --- a/JavaScriptCore/runtime/GlobalEvalFunction.cpp +++ b/JavaScriptCore/runtime/GlobalEvalFunction.cpp @@ -32,7 +32,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(GlobalEvalFunction); -GlobalEvalFunction::GlobalEvalFunction(ExecState* exec, PassRefPtr<Structure> structure, int len, const Identifier& name, NativeFunction function, JSGlobalObject* cachedGlobalObject) +GlobalEvalFunction::GlobalEvalFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int len, const Identifier& name, NativeFunction function, JSGlobalObject* cachedGlobalObject) : PrototypeFunction(exec, structure, len, name, function) , m_cachedGlobalObject(cachedGlobalObject) { diff --git a/JavaScriptCore/runtime/GlobalEvalFunction.h b/JavaScriptCore/runtime/GlobalEvalFunction.h index cdba4a0..389b1c3 100644 --- a/JavaScriptCore/runtime/GlobalEvalFunction.h +++ b/JavaScriptCore/runtime/GlobalEvalFunction.h @@ -32,9 +32,17 @@ namespace JSC { class GlobalEvalFunction : public PrototypeFunction { public: - GlobalEvalFunction(ExecState*, PassRefPtr<Structure>, int len, const Identifier&, NativeFunction, JSGlobalObject* expectedThisObject); + GlobalEvalFunction(ExecState*, NonNullPassRefPtr<Structure>, int len, const Identifier&, NativeFunction, JSGlobalObject* expectedThisObject); JSGlobalObject* cachedGlobalObject() const { return m_cachedGlobalObject; } + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); + } + + protected: + static const unsigned StructureFlags = ImplementsHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | PrototypeFunction::StructureFlags; + private: virtual void markChildren(MarkStack&); diff --git a/JavaScriptCore/runtime/Identifier.h b/JavaScriptCore/runtime/Identifier.h index 631cf42..2249179 100644 --- a/JavaScriptCore/runtime/Identifier.h +++ b/JavaScriptCore/runtime/Identifier.h @@ -54,6 +54,8 @@ namespace JSC { const char* ascii() const { return _ustring.ascii(); } static Identifier from(ExecState* exec, unsigned y) { return Identifier(exec, UString::from(y)); } + static Identifier from(ExecState* exec, int y) { return Identifier(exec, UString::from(y)); } + static Identifier from(ExecState* exec, double y) { return Identifier(exec, UString::from(y)); } bool isNull() const { return _ustring.isNull(); } bool isEmpty() const { return _ustring.isEmpty(); } diff --git a/JavaScriptCore/runtime/InitializeThreading.cpp b/JavaScriptCore/runtime/InitializeThreading.cpp index fea89f8..aad1af8 100644 --- a/JavaScriptCore/runtime/InitializeThreading.cpp +++ b/JavaScriptCore/runtime/InitializeThreading.cpp @@ -51,7 +51,7 @@ static void initializeThreadingOnce() initializeUString(); #if ENABLE(JSC_MULTIPLE_THREADS) s_dtoaP5Mutex = new Mutex; - WTF::initializeDates(); + initializeDates(); #endif } diff --git a/JavaScriptCore/runtime/InternalFunction.cpp b/JavaScriptCore/runtime/InternalFunction.cpp index b5c9571..c48d628 100644 --- a/JavaScriptCore/runtime/InternalFunction.cpp +++ b/JavaScriptCore/runtime/InternalFunction.cpp @@ -37,35 +37,35 @@ const ClassInfo* InternalFunction::classInfo() const return &info; } -InternalFunction::InternalFunction(JSGlobalData* globalData, PassRefPtr<Structure> structure, const Identifier& name) +InternalFunction::InternalFunction(JSGlobalData* globalData, NonNullPassRefPtr<Structure> structure, const Identifier& name) : JSObject(structure) { putDirect(globalData->propertyNames->name, jsString(globalData, name.ustring()), DontDelete | ReadOnly | DontEnum); } -const UString& InternalFunction::name(JSGlobalData* globalData) +const UString& InternalFunction::name(ExecState* exec) { - return asString(getDirect(globalData->propertyNames->name))->value(); + return asString(getDirect(exec->globalData().propertyNames->name))->value(exec); } -const UString InternalFunction::displayName(JSGlobalData* globalData) +const UString InternalFunction::displayName(ExecState* exec) { - JSValue displayName = getDirect(globalData->propertyNames->displayName); + JSValue displayName = getDirect(exec->globalData().propertyNames->displayName); - if (displayName && isJSString(globalData, displayName)) - return asString(displayName)->value(); + if (displayName && isJSString(&exec->globalData(), displayName)) + return asString(displayName)->value(exec); return UString::null(); } -const UString InternalFunction::calculatedDisplayName(JSGlobalData* globalData) +const UString InternalFunction::calculatedDisplayName(ExecState* exec) { - const UString explicitName = displayName(globalData); + const UString explicitName = displayName(exec); if (!explicitName.isEmpty()) return explicitName; - return name(globalData); + return name(exec); } } // namespace JSC diff --git a/JavaScriptCore/runtime/InternalFunction.h b/JavaScriptCore/runtime/InternalFunction.h index 310644c..fa1e5aa 100644 --- a/JavaScriptCore/runtime/InternalFunction.h +++ b/JavaScriptCore/runtime/InternalFunction.h @@ -36,18 +36,20 @@ namespace JSC { virtual const ClassInfo* classInfo() const; static JS_EXPORTDATA const ClassInfo info; - const UString& name(JSGlobalData*); - const UString displayName(JSGlobalData*); - const UString calculatedDisplayName(JSGlobalData*); + const UString& name(ExecState*); + const UString displayName(ExecState*); + const UString calculatedDisplayName(ExecState*); static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance | HasStandardGetOwnPropertySlot)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } protected: - InternalFunction(PassRefPtr<Structure> structure) : JSObject(structure) { } - InternalFunction(JSGlobalData*, PassRefPtr<Structure>, const Identifier&); + static const unsigned StructureFlags = ImplementsHasInstance | JSObject::StructureFlags; + + InternalFunction(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { } + InternalFunction(JSGlobalData*, NonNullPassRefPtr<Structure>, const Identifier&); private: virtual CallType getCallData(CallData&) = 0; diff --git a/JavaScriptCore/runtime/JSAPIValueWrapper.cpp b/JavaScriptCore/runtime/JSAPIValueWrapper.cpp index 475fad5..e83724a 100644 --- a/JavaScriptCore/runtime/JSAPIValueWrapper.cpp +++ b/JavaScriptCore/runtime/JSAPIValueWrapper.cpp @@ -28,40 +28,4 @@ namespace JSC { -JSValue JSAPIValueWrapper::toPrimitive(ExecState*, PreferredPrimitiveType) const -{ - ASSERT_NOT_REACHED(); - return JSValue(); -} - -bool JSAPIValueWrapper::getPrimitiveNumber(ExecState*, double&, JSValue&) -{ - ASSERT_NOT_REACHED(); - return false; -} - -bool JSAPIValueWrapper::toBoolean(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return false; -} - -double JSAPIValueWrapper::toNumber(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return 0; -} - -UString JSAPIValueWrapper::toString(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return UString(); -} - -JSObject* JSAPIValueWrapper::toObject(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return 0; -} - } // namespace JSC diff --git a/JavaScriptCore/runtime/JSAPIValueWrapper.h b/JavaScriptCore/runtime/JSAPIValueWrapper.h index 21a9710..aca550e 100644 --- a/JavaScriptCore/runtime/JSAPIValueWrapper.h +++ b/JavaScriptCore/runtime/JSAPIValueWrapper.h @@ -37,15 +37,9 @@ namespace JSC { virtual bool isAPIValueWrapper() const { return true; } - virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; - virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&); - virtual bool toBoolean(ExecState*) const; - virtual double toNumber(ExecState*) const; - virtual UString toString(ExecState*) const; - virtual JSObject* toObject(ExecState*) const; static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(CompoundType)); + return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren | OverridesGetPropertyNames)); } @@ -54,6 +48,7 @@ namespace JSC { : JSCell(exec->globalData().apiWrapperStructure.get()) , m_value(value) { + ASSERT(!value.isCell()); } JSValue m_value; diff --git a/JavaScriptCore/runtime/JSActivation.cpp b/JavaScriptCore/runtime/JSActivation.cpp index 87adbcd..22fdaaf 100644 --- a/JavaScriptCore/runtime/JSActivation.cpp +++ b/JavaScriptCore/runtime/JSActivation.cpp @@ -39,8 +39,8 @@ ASSERT_CLASS_FITS_IN_CELL(JSActivation); const ClassInfo JSActivation::info = { "JSActivation", 0, 0, 0 }; -JSActivation::JSActivation(CallFrame* callFrame, PassRefPtr<FunctionBodyNode> functionBody) - : Base(callFrame->globalData().activationStructure, new JSActivationData(functionBody, callFrame->registers())) +JSActivation::JSActivation(CallFrame* callFrame, NonNullPassRefPtr<FunctionExecutable> functionExecutable) + : Base(callFrame->globalData().activationStructure, new JSActivationData(functionExecutable, callFrame->registers())) { } @@ -57,12 +57,12 @@ void JSActivation::markChildren(MarkStack& markStack) if (!registerArray) return; - size_t numParametersMinusThis = d()->functionBody->generatedBytecode().m_numParameters - 1; + size_t numParametersMinusThis = d()->functionExecutable->parameterCount(); size_t count = numParametersMinusThis; markStack.appendValues(registerArray, count); - size_t numVars = d()->functionBody->generatedBytecode().m_numVars; + size_t numVars = d()->functionExecutable->variableCount(); // Skip the call frame, which sits between the parameters and vars. markStack.appendValues(registerArray + count + RegisterFile::CallFrameHeaderSize, numVars, MayContainNullValues); @@ -136,14 +136,14 @@ JSObject* JSActivation::toThisObject(ExecState* exec) const bool JSActivation::isDynamicScope() const { - return d()->functionBody->usesEval(); + return d()->functionExecutable->usesEval(); } JSValue JSActivation::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) { JSActivation* activation = asActivation(slot.slotBase()); - if (activation->d()->functionBody->usesArguments()) { + if (activation->d()->functionExecutable->usesArguments()) { PropertySlot slot; activation->symbolTableGet(exec->propertyNames().arguments, slot); return slot.getValue(exec, exec->propertyNames().arguments); @@ -156,7 +156,7 @@ JSValue JSActivation::argumentsGetter(ExecState* exec, const Identifier&, const arguments->copyRegisters(); callFrame->setCalleeArguments(arguments); } - ASSERT(arguments->isObject(&Arguments::info)); + ASSERT(arguments->inherits(&Arguments::info)); return arguments; } diff --git a/JavaScriptCore/runtime/JSActivation.h b/JavaScriptCore/runtime/JSActivation.h index 6a08439..ee98191 100644 --- a/JavaScriptCore/runtime/JSActivation.h +++ b/JavaScriptCore/runtime/JSActivation.h @@ -43,7 +43,7 @@ namespace JSC { class JSActivation : public JSVariableObject { typedef JSVariableObject Base; public: - JSActivation(CallFrame*, PassRefPtr<FunctionBodyNode>); + JSActivation(CallFrame*, NonNullPassRefPtr<FunctionExecutable>); virtual ~JSActivation(); virtual void markChildren(MarkStack&); @@ -66,17 +66,27 @@ namespace JSC { virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); } + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; private: struct JSActivationData : public JSVariableObjectData { - JSActivationData(PassRefPtr<FunctionBodyNode> functionBody, Register* registers) - : JSVariableObjectData(&functionBody->generatedBytecode().symbolTable(), registers) - , functionBody(functionBody) + JSActivationData(NonNullPassRefPtr<FunctionExecutable> _functionExecutable, Register* registers) + : JSVariableObjectData(_functionExecutable->generatedBytecode().symbolTable(), registers) + , functionExecutable(_functionExecutable) + { + // We have to manually ref and deref the symbol table as JSVariableObjectData + // doesn't know about SharedSymbolTable + functionExecutable->generatedBytecode().sharedSymbolTable()->ref(); + } + ~JSActivationData() { + static_cast<SharedSymbolTable*>(symbolTable)->deref(); } - RefPtr<FunctionBodyNode> functionBody; + RefPtr<FunctionExecutable> functionExecutable; }; static JSValue argumentsGetter(ExecState*, const Identifier&, const PropertySlot&); diff --git a/JavaScriptCore/runtime/JSArray.cpp b/JavaScriptCore/runtime/JSArray.cpp index 7d7d4c4..b16d3fa 100644 --- a/JavaScriptCore/runtime/JSArray.cpp +++ b/JavaScriptCore/runtime/JSArray.cpp @@ -25,6 +25,8 @@ #include "ArrayPrototype.h" #include "CachedCall.h" +#include "Error.h" +#include "Executable.h" #include "PropertyNameArray.h" #include <wtf/AVLTree.h> #include <wtf/Assertions.h> @@ -128,27 +130,25 @@ inline void JSArray::checkConsistency(ConsistencyCheckType) #endif -JSArray::JSArray(PassRefPtr<Structure> structure) +JSArray::JSArray(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { unsigned initialCapacity = 0; m_storage = static_cast<ArrayStorage*>(fastZeroedMalloc(storageSize(initialCapacity))); - m_storage->m_vectorLength = initialCapacity; - - m_fastAccessCutoff = 0; + m_vectorLength = initialCapacity; checkConsistency(); } -JSArray::JSArray(PassRefPtr<Structure> structure, unsigned initialLength) +JSArray::JSArray(NonNullPassRefPtr<Structure> structure, unsigned initialLength) : JSObject(structure) { unsigned initialCapacity = min(initialLength, MIN_SPARSE_ARRAY_INDEX); m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity))); m_storage->m_length = initialLength; - m_storage->m_vectorLength = initialCapacity; + m_vectorLength = initialCapacity; m_storage->m_numValuesInVector = 0; m_storage->m_sparseValueMap = 0; m_storage->lazyCreationData = 0; @@ -157,21 +157,19 @@ JSArray::JSArray(PassRefPtr<Structure> structure, unsigned initialLength) for (size_t i = 0; i < initialCapacity; ++i) vector[i] = JSValue(); - m_fastAccessCutoff = 0; - checkConsistency(); Heap::heap(this)->reportExtraMemoryCost(initialCapacity * sizeof(JSValue)); } -JSArray::JSArray(PassRefPtr<Structure> structure, const ArgList& list) +JSArray::JSArray(NonNullPassRefPtr<Structure> structure, const ArgList& list) : JSObject(structure) { unsigned initialCapacity = list.size(); m_storage = static_cast<ArrayStorage*>(fastMalloc(storageSize(initialCapacity))); m_storage->m_length = initialCapacity; - m_storage->m_vectorLength = initialCapacity; + m_vectorLength = initialCapacity; m_storage->m_numValuesInVector = initialCapacity; m_storage->m_sparseValueMap = 0; @@ -180,8 +178,6 @@ JSArray::JSArray(PassRefPtr<Structure> structure, const ArgList& list) for (ArgList::const_iterator it = list.begin(); it != end; ++it, ++i) m_storage->m_vector[i] = *it; - m_fastAccessCutoff = initialCapacity; - checkConsistency(); Heap::heap(this)->reportExtraMemoryCost(storageSize(initialCapacity)); @@ -205,7 +201,7 @@ bool JSArray::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot return false; } - if (i < storage->m_vectorLength) { + if (i < m_vectorLength) { JSValue& valueSlot = storage->m_vector[i]; if (valueSlot) { slot.setValueSlot(&valueSlot); @@ -221,7 +217,7 @@ bool JSArray::getOwnPropertySlot(ExecState* exec, unsigned i, PropertySlot& slot } } - return false; + return JSObject::getOwnPropertySlot(exec, Identifier::from(exec, i), slot); } bool JSArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) @@ -239,6 +235,37 @@ bool JSArray::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName return JSObject::getOwnPropertySlot(exec, propertyName, slot); } +bool JSArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + if (propertyName == exec->propertyNames().length) { + descriptor.setDescriptor(jsNumber(exec, length()), DontDelete | DontEnum); + return true; + } + + bool isArrayIndex; + unsigned i = propertyName.toArrayIndex(&isArrayIndex); + if (isArrayIndex) { + if (i >= m_storage->m_length) + return false; + if (i < m_vectorLength) { + JSValue& value = m_storage->m_vector[i]; + if (value) { + descriptor.setDescriptor(value, 0); + return true; + } + } else if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) { + if (i >= MIN_SPARSE_ARRAY_INDEX) { + SparseArrayValueMap::iterator it = map->find(i); + if (it != map->end()) { + descriptor.setDescriptor(it->second, 0); + return true; + } + } + } + } + return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); +} + // ECMA 15.4.5.1 void JSArray::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { @@ -272,7 +299,7 @@ void JSArray::put(ExecState* exec, unsigned i, JSValue value) m_storage->m_length = length; } - if (i < m_storage->m_vectorLength) { + if (i < m_vectorLength) { JSValue& valueSlot = m_storage->m_vector[i]; if (valueSlot) { valueSlot = value; @@ -280,8 +307,7 @@ void JSArray::put(ExecState* exec, unsigned i, JSValue value) return; } valueSlot = value; - if (++m_storage->m_numValuesInVector == m_storage->m_length) - m_fastAccessCutoff = m_storage->m_length; + ++m_storage->m_numValuesInVector; checkConsistency(); return; } @@ -319,8 +345,7 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu if (increaseVectorLength(i + 1)) { storage = m_storage; storage->m_vector[i] = value; - if (++storage->m_numValuesInVector == storage->m_length) - m_fastAccessCutoff = storage->m_length; + ++storage->m_numValuesInVector; checkConsistency(); } else throwOutOfMemoryError(exec); @@ -330,7 +355,7 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu // Decide how many values it would be best to move from the map. unsigned newNumValuesInVector = storage->m_numValuesInVector + 1; unsigned newVectorLength = increasedVectorLength(i + 1); - for (unsigned j = max(storage->m_vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) + for (unsigned j = max(m_vectorLength, MIN_SPARSE_ARRAY_INDEX); j < newVectorLength; ++j) newNumValuesInVector += map->contains(j); if (i >= MIN_SPARSE_ARRAY_INDEX) newNumValuesInVector -= map->contains(i); @@ -348,13 +373,12 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu } } - storage = static_cast<ArrayStorage*>(tryFastRealloc(storage, storageSize(newVectorLength))); - if (!storage) { + if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage)) { throwOutOfMemoryError(exec); return; } - unsigned vectorLength = storage->m_vectorLength; + unsigned vectorLength = m_vectorLength; Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); @@ -372,7 +396,7 @@ NEVER_INLINE void JSArray::putSlowCase(ExecState* exec, unsigned i, JSValue valu storage->m_vector[i] = value; - storage->m_vectorLength = newVectorLength; + m_vectorLength = newVectorLength; storage->m_numValuesInVector = newNumValuesInVector; m_storage = storage; @@ -399,7 +423,7 @@ bool JSArray::deleteProperty(ExecState* exec, unsigned i) ArrayStorage* storage = m_storage; - if (i < storage->m_vectorLength) { + if (i < m_vectorLength) { JSValue& valueSlot = storage->m_vector[i]; if (!valueSlot) { checkConsistency(); @@ -407,8 +431,6 @@ bool JSArray::deleteProperty(ExecState* exec, unsigned i) } valueSlot = JSValue(); --storage->m_numValuesInVector; - if (m_fastAccessCutoff > i) - m_fastAccessCutoff = i; checkConsistency(); return true; } @@ -432,7 +454,7 @@ bool JSArray::deleteProperty(ExecState* exec, unsigned i) return false; } -void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void JSArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { // FIXME: Filling PropertyNameArray with an identifier for every integer // is incredibly inefficient for large arrays. We need a different approach, @@ -440,7 +462,7 @@ void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames ArrayStorage* storage = m_storage; - unsigned usedVectorLength = min(storage->m_length, storage->m_vectorLength); + unsigned usedVectorLength = min(storage->m_length, m_vectorLength); for (unsigned i = 0; i < usedVectorLength; ++i) { if (storage->m_vector[i]) propertyNames.add(Identifier::from(exec, i)); @@ -452,7 +474,7 @@ void JSArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames propertyNames.add(Identifier::from(exec, it->first)); } - JSObject::getPropertyNames(exec, propertyNames); + JSObject::getOwnPropertyNames(exec, propertyNames); } bool JSArray::increaseVectorLength(unsigned newLength) @@ -462,17 +484,16 @@ bool JSArray::increaseVectorLength(unsigned newLength) ArrayStorage* storage = m_storage; - unsigned vectorLength = storage->m_vectorLength; + unsigned vectorLength = m_vectorLength; ASSERT(newLength > vectorLength); ASSERT(newLength <= MAX_STORAGE_VECTOR_INDEX); unsigned newVectorLength = increasedVectorLength(newLength); - storage = static_cast<ArrayStorage*>(tryFastRealloc(storage, storageSize(newVectorLength))); - if (!storage) + if (!tryFastRealloc(storage, storageSize(newVectorLength)).getValue(storage)) return false; Heap::heap(this)->reportExtraMemoryCost(storageSize(newVectorLength) - storageSize(vectorLength)); - storage->m_vectorLength = newVectorLength; + m_vectorLength = newVectorLength; for (unsigned i = vectorLength; i < newVectorLength; ++i) storage->m_vector[i] = JSValue(); @@ -490,10 +511,7 @@ void JSArray::setLength(unsigned newLength) unsigned length = m_storage->m_length; if (newLength < length) { - if (m_fastAccessCutoff > newLength) - m_fastAccessCutoff = newLength; - - unsigned usedVectorLength = min(length, storage->m_vectorLength); + unsigned usedVectorLength = min(length, m_vectorLength); for (unsigned i = newLength; i < usedVectorLength; ++i) { JSValue& valueSlot = storage->m_vector[i]; bool hadValue = valueSlot; @@ -532,20 +550,13 @@ JSValue JSArray::pop() JSValue result; - if (m_fastAccessCutoff > length) { - JSValue& valueSlot = m_storage->m_vector[length]; - result = valueSlot; - ASSERT(result); - valueSlot = JSValue(); - --m_storage->m_numValuesInVector; - m_fastAccessCutoff = length; - } else if (length < m_storage->m_vectorLength) { + if (length < m_vectorLength) { JSValue& valueSlot = m_storage->m_vector[length]; - result = valueSlot; - valueSlot = JSValue(); - if (result) + if (valueSlot) { --m_storage->m_numValuesInVector; - else + result = valueSlot; + valueSlot = JSValue(); + } else result = jsUndefined(); } else { result = jsUndefined(); @@ -573,11 +584,10 @@ void JSArray::push(ExecState* exec, JSValue value) { checkConsistency(); - if (m_storage->m_length < m_storage->m_vectorLength) { - ASSERT(!m_storage->m_vector[m_storage->m_length]); + if (m_storage->m_length < m_vectorLength) { m_storage->m_vector[m_storage->m_length] = value; - if (++m_storage->m_numValuesInVector == ++m_storage->m_length) - m_fastAccessCutoff = m_storage->m_length; + ++m_storage->m_numValuesInVector; + ++m_storage->m_length; checkConsistency(); return; } @@ -587,8 +597,8 @@ void JSArray::push(ExecState* exec, JSValue value) if (!map || map->isEmpty()) { if (increaseVectorLength(m_storage->m_length + 1)) { m_storage->m_vector[m_storage->m_length] = value; - if (++m_storage->m_numValuesInVector == ++m_storage->m_length) - m_fastAccessCutoff = m_storage->m_length; + ++m_storage->m_numValuesInVector; + ++m_storage->m_length; checkConsistency(); return; } @@ -603,18 +613,7 @@ void JSArray::push(ExecState* exec, JSValue value) void JSArray::markChildren(MarkStack& markStack) { - JSObject::markChildren(markStack); - - ArrayStorage* storage = m_storage; - - unsigned usedVectorLength = min(storage->m_length, storage->m_vectorLength); - markStack.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues); - - if (SparseArrayValueMap* map = storage->m_sparseValueMap) { - SparseArrayValueMap::iterator end = map->end(); - for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) - markStack.append(it->second); - } + markChildrenDirect(markStack); } static int compareNumbersForQSort(const void* a, const void* b) @@ -786,7 +785,7 @@ struct AVLTreeAbstractorForArrayCompare { m_cachedCall->setThis(m_globalThisValue); m_cachedCall->setArgument(0, va); m_cachedCall->setArgument(1, vb); - compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame()); + compareResult = m_cachedCall->call().toNumber(m_cachedCall->newCallFrame(m_exec)); } else { MarkedArgumentBuffer arguments; arguments.append(va); @@ -817,7 +816,7 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, if (!m_storage->m_length) return; - unsigned usedVectorLength = min(m_storage->m_length, m_storage->m_vectorLength); + unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength); AVLTree<AVLTreeAbstractorForArrayCompare, 44> tree; // Depth 44 is enough for 2^31 items tree.abstractor().m_exec = exec; @@ -866,7 +865,7 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, if (SparseArrayValueMap* map = m_storage->m_sparseValueMap) { newUsedVectorLength += map->size(); - if (newUsedVectorLength > m_storage->m_vectorLength) { + if (newUsedVectorLength > m_vectorLength) { // Check that it is possible to allocate an array large enough to hold all the entries. if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) { throwOutOfMemoryError(exec); @@ -906,7 +905,6 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) m_storage->m_vector[i] = JSValue(); - m_fastAccessCutoff = newUsedVectorLength; m_storage->m_numValuesInVector = newUsedVectorLength; checkConsistency(SortConsistencyCheck); @@ -914,10 +912,16 @@ void JSArray::sort(ExecState* exec, JSValue compareFunction, CallType callType, void JSArray::fillArgList(ExecState* exec, MarkedArgumentBuffer& args) { - unsigned fastAccessLength = min(m_storage->m_length, m_fastAccessCutoff); + JSValue* vector = m_storage->m_vector; + unsigned vectorEnd = min(m_storage->m_length, m_vectorLength); unsigned i = 0; - for (; i < fastAccessLength; ++i) - args.append(getIndex(i)); + for (; i < vectorEnd; ++i) { + JSValue& v = vector[i]; + if (!v) + break; + args.append(v); + } + for (; i < m_storage->m_length; ++i) args.append(get(exec, i)); } @@ -926,12 +930,17 @@ void JSArray::copyToRegisters(ExecState* exec, Register* buffer, uint32_t maxSiz { ASSERT(m_storage->m_length == maxSize); UNUSED_PARAM(maxSize); - unsigned fastAccessLength = min(m_storage->m_length, m_fastAccessCutoff); + JSValue* vector = m_storage->m_vector; + unsigned vectorEnd = min(m_storage->m_length, m_vectorLength); unsigned i = 0; - for (; i < fastAccessLength; ++i) - buffer[i] = getIndex(i); - uint32_t size = m_storage->m_length; - for (; i < size; ++i) + for (; i < vectorEnd; ++i) { + JSValue& v = vector[i]; + if (!v) + break; + buffer[i] = v; + } + + for (; i < m_storage->m_length; ++i) buffer[i] = get(exec, i); } @@ -941,7 +950,7 @@ unsigned JSArray::compactForSorting() ArrayStorage* storage = m_storage; - unsigned usedVectorLength = min(m_storage->m_length, storage->m_vectorLength); + unsigned usedVectorLength = min(m_storage->m_length, m_vectorLength); unsigned numDefined = 0; unsigned numUndefined = 0; @@ -965,7 +974,7 @@ unsigned JSArray::compactForSorting() if (SparseArrayValueMap* map = storage->m_sparseValueMap) { newUsedVectorLength += map->size(); - if (newUsedVectorLength > storage->m_vectorLength) { + if (newUsedVectorLength > m_vectorLength) { // Check that it is possible to allocate an array large enough to hold all the entries - if not, // exception is thrown by caller. if ((newUsedVectorLength > MAX_STORAGE_VECTOR_LENGTH) || !increaseVectorLength(newUsedVectorLength)) @@ -986,7 +995,6 @@ unsigned JSArray::compactForSorting() for (unsigned i = newUsedVectorLength; i < usedVectorLength; ++i) storage->m_vector[i] = JSValue(); - m_fastAccessCutoff = newUsedVectorLength; storage->m_numValuesInVector = newUsedVectorLength; checkConsistency(SortConsistencyCheck); @@ -1012,30 +1020,27 @@ void JSArray::checkConsistency(ConsistencyCheckType type) if (type == SortConsistencyCheck) ASSERT(!m_storage->m_sparseValueMap); - ASSERT(m_fastAccessCutoff <= m_storage->m_length); - ASSERT(m_fastAccessCutoff <= m_storage->m_numValuesInVector); - unsigned numValuesInVector = 0; - for (unsigned i = 0; i < m_storage->m_vectorLength; ++i) { + for (unsigned i = 0; i < m_vectorLength; ++i) { if (JSValue value = m_storage->m_vector[i]) { ASSERT(i < m_storage->m_length); if (type != DestructorConsistencyCheck) value->type(); // Likely to crash if the object was deallocated. ++numValuesInVector; } else { - ASSERT(i >= m_fastAccessCutoff); if (type == SortConsistencyCheck) ASSERT(i >= m_storage->m_numValuesInVector); } } ASSERT(numValuesInVector == m_storage->m_numValuesInVector); + ASSERT(numValuesInVector <= m_storage->m_length); if (m_storage->m_sparseValueMap) { SparseArrayValueMap::iterator end = m_storage->m_sparseValueMap->end(); for (SparseArrayValueMap::iterator it = m_storage->m_sparseValueMap->begin(); it != end; ++it) { unsigned index = it->first; ASSERT(index < m_storage->m_length); - ASSERT(index >= m_storage->m_vectorLength); + ASSERT(index >= m_vectorLength); ASSERT(index <= MAX_ARRAY_INDEX); ASSERT(it->second); if (type != DestructorConsistencyCheck) @@ -1046,26 +1051,4 @@ void JSArray::checkConsistency(ConsistencyCheckType type) #endif -JSArray* constructEmptyArray(ExecState* exec) -{ - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); -} - -JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) -{ - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength); -} - -JSArray* constructArray(ExecState* exec, JSValue singleItemValue) -{ - MarkedArgumentBuffer values; - values.append(singleItemValue); - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); -} - -JSArray* constructArray(ExecState* exec, const ArgList& values) -{ - return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); -} - } // namespace JSC diff --git a/JavaScriptCore/runtime/JSArray.h b/JavaScriptCore/runtime/JSArray.h index 49df6c4..8c22451 100644 --- a/JavaScriptCore/runtime/JSArray.h +++ b/JavaScriptCore/runtime/JSArray.h @@ -29,7 +29,6 @@ namespace JSC { struct ArrayStorage { unsigned m_length; - unsigned m_vectorLength; unsigned m_numValuesInVector; SparseArrayValueMap* m_sparseValueMap; void* lazyCreationData; // A JSArray subclass can use this to fill the vector lazily. @@ -38,15 +37,17 @@ namespace JSC { class JSArray : public JSObject { friend class JIT; + friend class Walker; public: - explicit JSArray(PassRefPtr<Structure>); - JSArray(PassRefPtr<Structure>, unsigned initialLength); - JSArray(PassRefPtr<Structure>, const ArgList& initialValues); + explicit JSArray(NonNullPassRefPtr<Structure>); + JSArray(NonNullPassRefPtr<Structure>, unsigned initialLength); + JSArray(NonNullPassRefPtr<Structure>, const ArgList& initialValues); virtual ~JSArray(); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState*, unsigned propertyName, JSValue); // FIXME: Make protected and add setItem. static JS_EXPORTDATA const ClassInfo info; @@ -61,18 +62,24 @@ namespace JSC { void push(ExecState*, JSValue); JSValue pop(); - bool canGetIndex(unsigned i) { return i < m_fastAccessCutoff; } + bool canGetIndex(unsigned i) { return i < m_vectorLength && m_storage->m_vector[i]; } JSValue getIndex(unsigned i) { ASSERT(canGetIndex(i)); return m_storage->m_vector[i]; } - bool canSetIndex(unsigned i) { return i < m_fastAccessCutoff; } - JSValue setIndex(unsigned i, JSValue v) + bool canSetIndex(unsigned i) { return i < m_vectorLength; } + void setIndex(unsigned i, JSValue v) { ASSERT(canSetIndex(i)); - return m_storage->m_vector[i] = v; + JSValue& x = m_storage->m_vector[i]; + if (!x) { + ++m_storage->m_numValuesInVector; + if (i >= m_storage->m_length) + m_storage->m_length = i + 1; + } + x = v; } void fillArgList(ExecState*, MarkedArgumentBuffer&); @@ -80,14 +87,17 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + + inline void markChildrenDirect(MarkStack& markStack); protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual bool deleteProperty(ExecState*, const Identifier& propertyName); virtual bool deleteProperty(ExecState*, unsigned propertyName); - virtual void getPropertyNames(ExecState*, PropertyNameArray&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&); virtual void markChildren(MarkStack&); void* lazyCreationData(); @@ -106,25 +116,110 @@ namespace JSC { enum ConsistencyCheckType { NormalConsistencyCheck, DestructorConsistencyCheck, SortConsistencyCheck }; void checkConsistency(ConsistencyCheckType = NormalConsistencyCheck); - unsigned m_fastAccessCutoff; + unsigned m_vectorLength; ArrayStorage* m_storage; }; JSArray* asArray(JSValue); - JSArray* constructEmptyArray(ExecState*); - JSArray* constructEmptyArray(ExecState*, unsigned initialLength); - JSArray* constructArray(ExecState*, JSValue singleItemValue); - JSArray* constructArray(ExecState*, const ArgList& values); + inline JSArray* asArray(JSCell* cell) + { + ASSERT(cell->inherits(&JSArray::info)); + return static_cast<JSArray*>(cell); + } inline JSArray* asArray(JSValue value) { - ASSERT(asObject(value)->inherits(&JSArray::info)); - return static_cast<JSArray*>(asObject(value)); + return asArray(value.asCell()); + } + + inline bool isJSArray(JSGlobalData* globalData, JSValue v) + { + return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr; + } + inline bool isJSArray(JSGlobalData* globalData, JSCell* cell) { return cell->vptr() == globalData->jsArrayVPtr; } + + inline void JSArray::markChildrenDirect(MarkStack& markStack) + { + JSObject::markChildrenDirect(markStack); + + ArrayStorage* storage = m_storage; + + unsigned usedVectorLength = std::min(storage->m_length, m_vectorLength); + markStack.appendValues(storage->m_vector, usedVectorLength, MayContainNullValues); + + if (SparseArrayValueMap* map = storage->m_sparseValueMap) { + SparseArrayValueMap::iterator end = map->end(); + for (SparseArrayValueMap::iterator it = map->begin(); it != end; ++it) + markStack.append(it->second); + } } - inline bool isJSArray(JSGlobalData* globalData, JSValue v) { return v.isCell() && v.asCell()->vptr() == globalData->jsArrayVPtr; } + inline void MarkStack::markChildren(JSCell* cell) + { + ASSERT(Heap::isCellMarked(cell)); + if (!cell->structure()->typeInfo().overridesMarkChildren()) { +#ifdef NDEBUG + asObject(cell)->markChildrenDirect(*this); +#else + ASSERT(!m_isCheckingForDefaultMarkViolation); + m_isCheckingForDefaultMarkViolation = true; + cell->markChildren(*this); + ASSERT(m_isCheckingForDefaultMarkViolation); + m_isCheckingForDefaultMarkViolation = false; +#endif + return; + } + if (cell->vptr() == m_jsArrayVPtr) { + asArray(cell)->markChildrenDirect(*this); + return; + } + cell->markChildren(*this); + } + inline void MarkStack::drain() + { + while (!m_markSets.isEmpty() || !m_values.isEmpty()) { + while (!m_markSets.isEmpty() && m_values.size() < 50) { + ASSERT(!m_markSets.isEmpty()); + MarkSet& current = m_markSets.last(); + ASSERT(current.m_values); + JSValue* end = current.m_end; + ASSERT(current.m_values); + ASSERT(current.m_values != end); + findNextUnmarkedNullValue: + ASSERT(current.m_values != end); + JSValue value = *current.m_values; + current.m_values++; + + JSCell* cell; + if (!value || !value.isCell() || Heap::isCellMarked(cell = value.asCell())) { + if (current.m_values == end) { + m_markSets.removeLast(); + continue; + } + goto findNextUnmarkedNullValue; + } + + Heap::markCell(cell); + if (cell->structure()->typeInfo().type() < CompoundType) { + if (current.m_values == end) { + m_markSets.removeLast(); + continue; + } + goto findNextUnmarkedNullValue; + } + + if (current.m_values == end) + m_markSets.removeLast(); + + markChildren(cell); + } + while (!m_values.isEmpty()) + markChildren(m_values.removeLast()); + } + } + } // namespace JSC #endif // JSArray_h diff --git a/JavaScriptCore/runtime/JSByteArray.cpp b/JavaScriptCore/runtime/JSByteArray.cpp index 2a5e72f..5e5003b 100644 --- a/JavaScriptCore/runtime/JSByteArray.cpp +++ b/JavaScriptCore/runtime/JSByteArray.cpp @@ -35,7 +35,7 @@ namespace JSC { const ClassInfo JSByteArray::s_defaultInfo = { "ByteArray", 0, 0, 0 }; -JSByteArray::JSByteArray(ExecState* exec, PassRefPtr<Structure> structure, ByteArray* storage, const JSC::ClassInfo* classInfo) +JSByteArray::JSByteArray(ExecState* exec, NonNullPassRefPtr<Structure> structure, ByteArray* storage, const JSC::ClassInfo* classInfo) : JSObject(structure) , m_storage(storage) , m_classInfo(classInfo) @@ -45,7 +45,7 @@ JSByteArray::JSByteArray(ExecState* exec, PassRefPtr<Structure> structure, ByteA PassRefPtr<Structure> JSByteArray::createStructure(JSValue prototype) { - PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType)); + PassRefPtr<Structure> result = Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); return result; } @@ -59,7 +59,18 @@ bool JSByteArray::getOwnPropertySlot(ExecState* exec, const Identifier& property } return JSObject::getOwnPropertySlot(exec, propertyName, slot); } - + +bool JSByteArray::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + bool ok; + unsigned index = propertyName.toUInt32(&ok, false); + if (ok && canAccessIndex(index)) { + descriptor.setDescriptor(getIndex(exec, index), DontDelete); + return true; + } + return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); +} + bool JSByteArray::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) { if (canAccessIndex(propertyName)) { @@ -85,12 +96,12 @@ void JSByteArray::put(ExecState* exec, unsigned propertyName, JSValue value) setIndex(exec, propertyName, value); } -void JSByteArray::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void JSByteArray::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { unsigned length = m_storage->length(); for (unsigned i = 0; i < length; ++i) propertyNames.add(Identifier::from(exec, i)); - JSObject::getPropertyNames(exec, propertyNames); + JSObject::getOwnPropertyNames(exec, propertyNames); } } diff --git a/JavaScriptCore/runtime/JSByteArray.h b/JavaScriptCore/runtime/JSByteArray.h index a56aca6..fe6e124 100644 --- a/JavaScriptCore/runtime/JSByteArray.h +++ b/JavaScriptCore/runtime/JSByteArray.h @@ -73,15 +73,16 @@ namespace JSC { setIndex(i, byteValue); } - JSByteArray(ExecState* exec, PassRefPtr<Structure>, WTF::ByteArray* storage, const JSC::ClassInfo* = &s_defaultInfo); + JSByteArray(ExecState* exec, NonNullPassRefPtr<Structure>, WTF::ByteArray* storage, const JSC::ClassInfo* = &s_defaultInfo); static PassRefPtr<Structure> createStructure(JSValue prototype); virtual bool getOwnPropertySlot(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::PropertySlot&); virtual bool getOwnPropertySlot(JSC::ExecState*, unsigned propertyName, JSC::PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(JSC::ExecState*, const JSC::Identifier& propertyName, JSC::JSValue, JSC::PutPropertySlot&); virtual void put(JSC::ExecState*, unsigned propertyName, JSC::JSValue); - virtual void getPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&); + virtual void getOwnPropertyNames(JSC::ExecState*, JSC::PropertyNameArray&); virtual const ClassInfo* classInfo() const { return m_classInfo; } static const ClassInfo s_defaultInfo; @@ -90,6 +91,9 @@ namespace JSC { WTF::ByteArray* storage() const { return m_storage.get(); } + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesGetPropertyNames | JSObject::StructureFlags; + private: enum VPtrStealingHackType { VPtrStealingHack }; JSByteArray(VPtrStealingHackType) diff --git a/JavaScriptCore/runtime/JSCell.cpp b/JavaScriptCore/runtime/JSCell.cpp index c733ed9..17410e2 100644 --- a/JavaScriptCore/runtime/JSCell.cpp +++ b/JavaScriptCore/runtime/JSCell.cpp @@ -78,11 +78,7 @@ extern const double Inf = NaNInf.doubles.Inf_Double; void* JSCell::operator new(size_t size, ExecState* exec) { -#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return exec->heap()->inlineAllocate(size); -#else return exec->heap()->allocate(size); -#endif } bool JSCell::getUInt32(uint32_t&) const @@ -90,22 +86,22 @@ bool JSCell::getUInt32(uint32_t&) const return false; } -bool JSCell::getString(UString&stringValue) const +bool JSCell::getString(ExecState* exec, UString&stringValue) const { if (!isString()) return false; - stringValue = static_cast<const JSString*>(this)->value(); + stringValue = static_cast<const JSString*>(this)->value(exec); return true; } -UString JSCell::getString() const +UString JSCell::getString(ExecState* exec) const { - return isString() ? static_cast<const JSString*>(this)->value() : UString(); + return isString() ? static_cast<const JSString*>(this)->value(exec) : UString(); } JSObject* JSCell::getObject() { - return isObject() ? static_cast<JSObject*>(this) : 0; + return isObject() ? asObject(this) : 0; } const JSObject* JSCell::getObject() const @@ -197,4 +193,40 @@ bool JSCell::isGetterSetter() const return false; } +JSValue JSCell::toPrimitive(ExecState*, PreferredPrimitiveType) const +{ + ASSERT_NOT_REACHED(); + return JSValue(); +} + +bool JSCell::getPrimitiveNumber(ExecState*, double&, JSValue&) +{ + ASSERT_NOT_REACHED(); + return false; +} + +bool JSCell::toBoolean(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return false; +} + +double JSCell::toNumber(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return 0; +} + +UString JSCell::toString(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return UString(); +} + +JSObject* JSCell::toObject(ExecState*) const +{ + ASSERT_NOT_REACHED(); + return 0; +} + } // namespace JSC diff --git a/JavaScriptCore/runtime/JSCell.h b/JavaScriptCore/runtime/JSCell.h index 75ccf7f..c8ba2b8 100644 --- a/JavaScriptCore/runtime/JSCell.h +++ b/JavaScriptCore/runtime/JSCell.h @@ -23,11 +23,12 @@ #ifndef JSCell_h #define JSCell_h -#include <wtf/Noncopyable.h> -#include "Structure.h" -#include "JSValue.h" -#include "JSImmediate.h" #include "Collector.h" +#include "JSImmediate.h" +#include "JSValue.h" +#include "MarkStack.h" +#include "Structure.h" +#include <wtf/Noncopyable.h> namespace JSC { @@ -41,10 +42,12 @@ namespace JSC { friend class JSString; friend class JSValue; friend class JSAPIValueWrapper; + friend class JSZombie; friend struct VPtrSet; private: explicit JSCell(Structure*); + JSCell(); // Only used for initializing Collector blocks. virtual ~JSCell(); public: @@ -55,14 +58,15 @@ namespace JSC { bool isString() const; bool isObject() const; virtual bool isGetterSetter() const; - virtual bool isObject(const ClassInfo*) const; + bool inherits(const ClassInfo*) const; virtual bool isAPIValueWrapper() const { return false; } + virtual bool isPropertyNameIterator() const { return false; } Structure* structure() const; // Extracting the value. - bool getString(UString&) const; - UString getString() const; // null string if not a string + bool getString(ExecState* exec, UString&) const; + UString getString(ExecState* exec) const; // null string if not a string JSObject* getObject(); // NULL if not an object const JSObject* getObject() const; // NULL if not an object @@ -74,21 +78,22 @@ namespace JSC { virtual bool getUInt32(uint32_t&) const; // Basic conversions. - virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const = 0; - virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&) = 0; - virtual bool toBoolean(ExecState*) const = 0; - virtual double toNumber(ExecState*) const = 0; - virtual UString toString(ExecState*) const = 0; - virtual JSObject* toObject(ExecState*) const = 0; + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; + virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&); + virtual bool toBoolean(ExecState*) const; + virtual double toNumber(ExecState*) const; + virtual UString toString(ExecState*) const; + virtual JSObject* toObject(ExecState*) const; // Garbage collection. void* operator new(size_t, ExecState*); void* operator new(size_t, JSGlobalData*); void* operator new(size_t, void* placementNewDestination) { return placementNewDestination; } - void markCellDirect(); virtual void markChildren(MarkStack&); - bool marked() const; +#if ENABLE(JSC_ZOMBIES) + virtual bool isZombie() const { return false; } +#endif // Object operations, with the toObject operation included. virtual const ClassInfo* classInfo() const; @@ -112,15 +117,13 @@ namespace JSC { Structure* m_structure; }; - JSCell* asCell(JSValue); - - inline JSCell* asCell(JSValue value) + inline JSCell::JSCell(Structure* structure) + : m_structure(structure) { - return value.asCell(); } - inline JSCell::JSCell(Structure* structure) - : m_structure(structure) + // Only used for initializing Collector blocks. + inline JSCell::JSCell() { } @@ -150,28 +153,13 @@ namespace JSC { return m_structure; } - inline bool JSCell::marked() const - { - return Heap::isCellMarked(this); - } - - inline void JSCell::markCellDirect() - { - Heap::markCell(this); - } - inline void JSCell::markChildren(MarkStack&) { - ASSERT(marked()); } inline void* JSCell::operator new(size_t size, JSGlobalData* globalData) { -#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return globalData->heap.inlineAllocate(size); -#else return globalData->heap.allocate(size); -#endif } // --- JSValue inlines ---------------------------- @@ -191,14 +179,14 @@ namespace JSC { return isCell() && asCell()->isObject(); } - inline bool JSValue::getString(UString& s) const + inline bool JSValue::getString(ExecState* exec, UString& s) const { - return isCell() && asCell()->getString(s); + return isCell() && asCell()->getString(exec, s); } - inline UString JSValue::getString() const + inline UString JSValue::getString(ExecState* exec) const { - return isCell() ? asCell()->getString() : UString(); + return isCell() ? asCell()->getString(exec) : UString(); } inline JSObject* JSValue::getObject() const @@ -231,23 +219,6 @@ namespace JSC { return false; } - inline void JSValue::markDirect() - { - ASSERT(!marked()); - asCell()->markCellDirect(); - } - - inline void JSValue::markChildren(MarkStack& markStack) - { - ASSERT(marked()); - asCell()->markChildren(markStack); - } - - inline bool JSValue::marked() const - { - return !isCell() || asCell()->marked(); - } - #if !USE(JSVALUE32_64) ALWAYS_INLINE JSCell* JSValue::asCell() const { @@ -315,24 +286,6 @@ namespace JSC { return isUndefined() ? nonInlineNaN() : 0; // null and false both convert to 0. } - inline UString JSValue::toString(ExecState* exec) const - { - if (isCell()) - return asCell()->toString(exec); - if (isInt32()) - return UString::from(asInt32()); - if (isDouble()) - return asDouble() == 0.0 ? "0" : UString::from(asDouble()); - if (isTrue()) - return "true"; - if (isFalse()) - return "false"; - if (isNull()) - return "null"; - ASSERT(isUndefined()); - return "undefined"; - } - inline bool JSValue::needsThisConversion() const { if (UNLIKELY(!isCell())) @@ -353,12 +306,6 @@ namespace JSC { return asCell()->getJSNumber(); return JSValue(); } - - inline bool JSValue::hasChildren() const - { - return asCell()->structure()->typeInfo().type() >= CompoundType; - } - inline JSObject* JSValue::toObject(ExecState* exec) const { @@ -372,37 +319,40 @@ namespace JSC { ALWAYS_INLINE void MarkStack::append(JSCell* cell) { + ASSERT(!m_isCheckingForDefaultMarkViolation); ASSERT(cell); - if (cell->marked()) + if (Heap::isCellMarked(cell)) return; - cell->markCellDirect(); + Heap::markCell(cell); if (cell->structure()->typeInfo().type() >= CompoundType) m_values.append(cell); } - inline void MarkStack::drain() { - while (!m_markSets.isEmpty() || !m_values.isEmpty()) { - while ((!m_markSets.isEmpty()) && m_values.size() < 50) { - const MarkSet& current = m_markSets.removeLast(); - JSValue* ptr = current.m_values; - JSValue* end = current.m_end; - if (current.m_properties == NoNullValues) { - while (ptr != end) - append(*ptr++); - } else { - while (ptr != end) { - if (JSValue value = *ptr++) - append(value); - } - } - } - while (!m_values.isEmpty()) { - JSCell* current = m_values.removeLast(); - ASSERT(current->marked()); - current->markChildren(*this); - } - } + ALWAYS_INLINE void MarkStack::append(JSValue value) + { + ASSERT(value); + if (value.isCell()) + append(value.asCell()); } + + inline Heap* Heap::heap(JSValue v) + { + if (!v.isCell()) + return 0; + return heap(v.asCell()); + } + + inline Heap* Heap::heap(JSCell* c) + { + return cellBlock(c)->heap; + } + +#if ENABLE(JSC_ZOMBIES) + inline bool JSValue::isZombie() const + { + return isCell() && asCell() && asCell()->isZombie(); + } +#endif } // namespace JSC #endif // JSCell_h diff --git a/JavaScriptCore/runtime/JSFunction.cpp b/JavaScriptCore/runtime/JSFunction.cpp index 84c6263..024e586 100644 --- a/JavaScriptCore/runtime/JSFunction.cpp +++ b/JavaScriptCore/runtime/JSFunction.cpp @@ -45,12 +45,21 @@ ASSERT_CLASS_FITS_IN_CELL(JSFunction); const ClassInfo JSFunction::info = { "Function", &InternalFunction::info, 0, 0 }; -JSFunction::JSFunction(ExecState* exec, PassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func) +bool JSFunction::isHostFunctionNonInline() const +{ + return isHostFunction(); +} + +JSFunction::JSFunction(NonNullPassRefPtr<Structure> structure) + : Base(structure) + , m_executable(adoptRef(new VPtrHackExecutable())) +{ +} + +JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<Structure> structure, int length, const Identifier& name, NativeFunction func) : Base(&exec->globalData(), structure, name) #if ENABLE(JIT) - , m_body(FunctionBodyNode::createNativeThunk(&exec->globalData())) -#else - , m_body(0) + , m_executable(adoptRef(new NativeExecutable(exec))) #endif { #if ENABLE(JIT) @@ -63,9 +72,9 @@ JSFunction::JSFunction(ExecState* exec, PassRefPtr<Structure> structure, int len #endif } -JSFunction::JSFunction(ExecState* exec, const Identifier& name, FunctionBodyNode* body, ScopeChainNode* scopeChainNode) - : Base(&exec->globalData(), exec->lexicalGlobalObject()->functionStructure(), name) - , m_body(body) +JSFunction::JSFunction(ExecState* exec, NonNullPassRefPtr<FunctionExecutable> executable, ScopeChainNode* scopeChainNode) + : Base(&exec->globalData(), exec->lexicalGlobalObject()->functionStructure(), executable->name()) + , m_executable(executable) { setScopeChain(scopeChainNode); } @@ -75,20 +84,23 @@ JSFunction::~JSFunction() // JIT code for other functions may have had calls linked directly to the code for this function; these links // are based on a check for the this pointer value for this JSFunction - which will no longer be valid once // this memory is freed and may be reused (potentially for another, different JSFunction). + if (!isHostFunction()) { #if ENABLE(JIT_OPTIMIZE_CALL) - if (m_body && m_body->isGenerated()) - m_body->generatedBytecode().unlinkCallers(); + ASSERT(m_executable); + if (jsExecutable()->isGenerated()) + jsExecutable()->generatedBytecode().unlinkCallers(); #endif - if (!isHostFunction()) scopeChain().~ScopeChain(); // FIXME: Don't we need to do this in the interpreter too? + } } void JSFunction::markChildren(MarkStack& markStack) { Base::markChildren(markStack); - m_body->markAggregate(markStack); - if (!isHostFunction()) + if (!isHostFunction()) { + jsExecutable()->markAggregate(markStack); scopeChain().markAggregate(markStack); + } } CallType JSFunction::getCallData(CallData& callData) @@ -97,7 +109,7 @@ CallType JSFunction::getCallData(CallData& callData) callData.native.function = nativeFunction(); return CallTypeHost; } - callData.js.functionBody = m_body.get(); + callData.js.functionExecutable = jsExecutable(); callData.js.scopeChain = scopeChain().node(); return CallTypeJS; } @@ -105,7 +117,7 @@ CallType JSFunction::getCallData(CallData& callData) JSValue JSFunction::call(ExecState* exec, JSValue thisValue, const ArgList& args) { ASSERT(!isHostFunction()); - return exec->interpreter()->execute(m_body.get(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot()); + return exec->interpreter()->execute(jsExecutable(), exec, this, thisValue.toThisObject(exec), args, scopeChain().node(), exec->exceptionSlot()); } JSValue JSFunction::argumentsGetter(ExecState* exec, const Identifier&, const PropertySlot& slot) @@ -126,7 +138,7 @@ JSValue JSFunction::lengthGetter(ExecState* exec, const Identifier&, const Prope { JSFunction* thisObj = asFunction(slot.slotBase()); ASSERT(!thisObj->isHostFunction()); - return jsNumber(exec, thisObj->m_body->parameterCount()); + return jsNumber(exec, thisObj->jsExecutable()->parameterCount()); } bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) @@ -165,6 +177,35 @@ bool JSFunction::getOwnPropertySlot(ExecState* exec, const Identifier& propertyN return Base::getOwnPropertySlot(exec, propertyName, slot); } + bool JSFunction::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) + { + if (isHostFunction()) + return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); + + if (propertyName == exec->propertyNames().prototype) { + PropertySlot slot; + getOwnPropertySlot(exec, propertyName, slot); + return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); + } + + if (propertyName == exec->propertyNames().arguments) { + descriptor.setDescriptor(exec->interpreter()->retrieveArguments(exec, this), ReadOnly | DontEnum | DontDelete); + return true; + } + + if (propertyName == exec->propertyNames().length) { + descriptor.setDescriptor(jsNumber(exec, jsExecutable()->parameterCount()), ReadOnly | DontEnum | DontDelete); + return true; + } + + if (propertyName == exec->propertyNames().caller) { + descriptor.setDescriptor(exec->interpreter()->retrieveCaller(exec, this), ReadOnly | DontEnum | DontDelete); + return true; + } + + return Base::getOwnPropertyDescriptor(exec, propertyName, descriptor); + } + void JSFunction::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { if (isHostFunction()) { @@ -190,7 +231,7 @@ ConstructType JSFunction::getConstructData(ConstructData& constructData) { if (isHostFunction()) return ConstructTypeNone; - constructData.js.functionBody = m_body.get(); + constructData.js.functionExecutable = jsExecutable(); constructData.js.scopeChain = scopeChain().node(); return ConstructTypeJS; } @@ -206,7 +247,7 @@ JSObject* JSFunction::construct(ExecState* exec, const ArgList& args) structure = exec->lexicalGlobalObject()->emptyObjectStructure(); JSObject* thisObj = new (exec) JSObject(structure); - JSValue result = exec->interpreter()->execute(m_body.get(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot()); + JSValue result = exec->interpreter()->execute(jsExecutable(), exec, this, thisObj, args, scopeChain().node(), exec->exceptionSlot()); if (exec->hadException() || !result.isObject()) return thisObj; return asObject(result); diff --git a/JavaScriptCore/runtime/JSFunction.h b/JavaScriptCore/runtime/JSFunction.h index cab1e5b..fcac9aa 100644 --- a/JavaScriptCore/runtime/JSFunction.h +++ b/JavaScriptCore/runtime/JSFunction.h @@ -25,14 +25,11 @@ #define JSFunction_h #include "InternalFunction.h" -#include "JSVariableObject.h" -#include "SymbolTable.h" -#include "Nodes.h" -#include "JSObject.h" namespace JSC { - class FunctionBodyNode; + class ExecutableBase; + class FunctionExecutable; class FunctionPrototype; class JSActivation; class JSGlobalObject; @@ -43,20 +40,10 @@ namespace JSC { typedef InternalFunction Base; - JSFunction(PassRefPtr<Structure> structure) - : InternalFunction(structure) - { - clearScopeChain(); - } - public: - JSFunction(ExecState*, PassRefPtr<Structure>, int length, const Identifier&, NativeFunction); - JSFunction(ExecState*, const Identifier&, FunctionBodyNode*, ScopeChainNode*); - ~JSFunction(); - - virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); - virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); - virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + JSFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeFunction); + JSFunction(ExecState*, NonNullPassRefPtr<FunctionExecutable>, ScopeChainNode*); + virtual ~JSFunction(); JSObject* construct(ExecState*, const ArgList&); JSValue call(ExecState*, JSValue thisValue, const ArgList&); @@ -64,63 +51,72 @@ namespace JSC { void setScope(const ScopeChain& scopeChain) { setScopeChain(scopeChain); } ScopeChain& scope() { return scopeChain(); } - void setBody(FunctionBodyNode* body) { m_body = body; } - void setBody(PassRefPtr<FunctionBodyNode> body) { m_body = body; } - FunctionBodyNode* body() const { return m_body.get(); } + ExecutableBase* executable() const { return m_executable.get(); } - virtual void markChildren(MarkStack&); + // To call either of these methods include Executable.h + inline bool isHostFunction() const; + FunctionExecutable* jsExecutable() const; static JS_EXPORTDATA const ClassInfo info; static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } -#if ENABLE(JIT) - bool isHostFunction() const { return m_body && m_body->isHostFunction(); } -#else - bool isHostFunction() const { return false; } -#endif NativeFunction nativeFunction() { - return *reinterpret_cast<NativeFunction*>(m_data); + return *WTF::bitwise_cast<NativeFunction*>(m_data); } virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); + protected: + const static unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | OverridesMarkChildren | OverridesGetPropertyNames | InternalFunction::StructureFlags; + private: + JSFunction(NonNullPassRefPtr<Structure>); + + bool isHostFunctionNonInline() const; + + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); + virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); + virtual bool deleteProperty(ExecState*, const Identifier& propertyName); + + virtual void markChildren(MarkStack&); + virtual const ClassInfo* classInfo() const { return &info; } static JSValue argumentsGetter(ExecState*, const Identifier&, const PropertySlot&); static JSValue callerGetter(ExecState*, const Identifier&, const PropertySlot&); static JSValue lengthGetter(ExecState*, const Identifier&, const PropertySlot&); - RefPtr<FunctionBodyNode> m_body; + RefPtr<ExecutableBase> m_executable; ScopeChain& scopeChain() { - ASSERT(!isHostFunction()); - return *reinterpret_cast<ScopeChain*>(m_data); + ASSERT(!isHostFunctionNonInline()); + return *WTF::bitwise_cast<ScopeChain*>(m_data); } void clearScopeChain() { - ASSERT(!isHostFunction()); + ASSERT(!isHostFunctionNonInline()); new (m_data) ScopeChain(NoScopeChain()); } void setScopeChain(ScopeChainNode* sc) { - ASSERT(!isHostFunction()); + ASSERT(!isHostFunctionNonInline()); new (m_data) ScopeChain(sc); } void setScopeChain(const ScopeChain& sc) { - ASSERT(!isHostFunction()); - *reinterpret_cast<ScopeChain*>(m_data) = sc; + ASSERT(!isHostFunctionNonInline()); + *WTF::bitwise_cast<ScopeChain*>(m_data) = sc; } void setNativeFunction(NativeFunction func) { - *reinterpret_cast<NativeFunction*>(m_data) = func; + *WTF::bitwise_cast<NativeFunction*>(m_data) = func; } unsigned char m_data[sizeof(void*)]; }; diff --git a/JavaScriptCore/runtime/JSGlobalData.cpp b/JavaScriptCore/runtime/JSGlobalData.cpp index 03df41d..234449f 100644 --- a/JavaScriptCore/runtime/JSGlobalData.cpp +++ b/JavaScriptCore/runtime/JSGlobalData.cpp @@ -82,26 +82,28 @@ struct VPtrSet { VPtrSet::VPtrSet() { - // Bizarrely, calling fastMalloc here is faster than allocating space on the stack. - void* storage = fastMalloc(sizeof(CollectorBlock)); + CollectorCell cell; + void* storage = &cell; + COMPILE_ASSERT(sizeof(JSArray) <= sizeof(CollectorCell), sizeof_JSArray_must_be_less_than_CollectorCell); JSCell* jsArray = new (storage) JSArray(JSArray::createStructure(jsNull())); jsArrayVPtr = jsArray->vptr(); jsArray->~JSCell(); + COMPILE_ASSERT(sizeof(JSByteArray) <= sizeof(CollectorCell), sizeof_JSByteArray_must_be_less_than_CollectorCell); JSCell* jsByteArray = new (storage) JSByteArray(JSByteArray::VPtrStealingHack); jsByteArrayVPtr = jsByteArray->vptr(); jsByteArray->~JSCell(); + COMPILE_ASSERT(sizeof(JSString) <= sizeof(CollectorCell), sizeof_JSString_must_be_less_than_CollectorCell); JSCell* jsString = new (storage) JSString(JSString::VPtrStealingHack); jsStringVPtr = jsString->vptr(); jsString->~JSCell(); + COMPILE_ASSERT(sizeof(JSFunction) <= sizeof(CollectorCell), sizeof_JSFunction_must_be_less_than_CollectorCell); JSCell* jsFunction = new (storage) JSFunction(JSFunction::createStructure(jsNull())); jsFunctionVPtr = jsFunction->vptr(); jsFunction->~JSCell(); - - fastFree(storage); } JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet) @@ -144,8 +146,14 @@ JSGlobalData::JSGlobalData(bool isShared, const VPtrSet& vptrSet) , initializingLazyNumericCompareFunction(false) , head(0) , dynamicGlobalObject(0) - , scopeNodeBeingReparsed(0) + , functionCodeBlockBeingReparsed(0) , firstStringifierToMark(0) + , markStack(vptrSet.jsArrayVPtr) + , cachedUTCOffset(NaN) + , weakRandom(static_cast<int>(currentTime())) +#ifndef NDEBUG + , mainThreadOnly(false) +#endif { #if PLATFORM(MAC) startProfilerServerIfNeeded(); @@ -235,9 +243,8 @@ const Vector<Instruction>& JSGlobalData::numericCompareFunction(ExecState* exec) { if (!lazyNumericCompareFunction.size() && !initializingLazyNumericCompareFunction) { initializingLazyNumericCompareFunction = true; - RefPtr<ProgramNode> programNode = parser->parse<ProgramNode>(exec, 0, makeSource(UString("(function (v1, v2) { return v1 - v2; })")), 0, 0); - RefPtr<FunctionBodyNode> functionBody = extractFunctionBody(programNode.get()); - lazyNumericCompareFunction = functionBody->bytecode(exec->scopeChain()).instructions(); + RefPtr<FunctionExecutable> function = FunctionExecutable::fromGlobalCode(Identifier(exec, "numericCompare"), exec, 0, makeSource(UString("(function (v1, v2) { return v1 - v2; })")), 0, 0); + lazyNumericCompareFunction = function->bytecode(exec, exec->scopeChain()).instructions(); initializingLazyNumericCompareFunction = false; } @@ -248,4 +255,27 @@ JSGlobalData::ClientData::~ClientData() { } +void JSGlobalData::resetDateCache() +{ + cachedUTCOffset = NaN; + dstOffsetCache.reset(); + cachedDateString = UString(); + dateInstanceCache.reset(); +} + +void JSGlobalData::startSampling() +{ + interpreter->startSampling(); +} + +void JSGlobalData::stopSampling() +{ + interpreter->stopSampling(); +} + +void JSGlobalData::dumpSampleData(ExecState* exec) +{ + interpreter->dumpSampleData(exec); +} + } // namespace JSC diff --git a/JavaScriptCore/runtime/JSGlobalData.h b/JavaScriptCore/runtime/JSGlobalData.h index 88cb516..f0c1b5c 100644 --- a/JavaScriptCore/runtime/JSGlobalData.h +++ b/JavaScriptCore/runtime/JSGlobalData.h @@ -30,12 +30,15 @@ #define JSGlobalData_h #include "Collector.h" +#include "DateInstanceCache.h" #include "ExecutableAllocator.h" #include "JITStubs.h" #include "JSValue.h" #include "MarkStack.h" +#include "NumericStrings.h" #include "SmallStrings.h" #include "TimeoutChecker.h" +#include "WeakRandom.h" #include <wtf/Forward.h> #include <wtf/HashMap.h> #include <wtf/RefCounted.h> @@ -45,15 +48,14 @@ struct OpaqueJSClassContextData; namespace JSC { + class CodeBlock; class CommonIdentifiers; - class FunctionBodyNode; class IdentifierTable; class Interpreter; class JSGlobalObject; class JSObject; class Lexer; class Parser; - class ScopeNode; class Stringifier; class Structure; class UString; @@ -62,6 +64,26 @@ namespace JSC { struct Instruction; struct VPtrSet; + struct DSTOffsetCache { + DSTOffsetCache() + { + reset(); + } + + void reset() + { + offset = 0.0; + start = 0.0; + end = -1.0; + increment = 0.0; + } + + double offset; + double start; + double end; + double increment; + }; + class JSGlobalData : public RefCounted<JSGlobalData> { public: struct ClientData { @@ -115,7 +137,9 @@ namespace JSC { CommonIdentifiers* propertyNames; const MarkedArgumentBuffer* emptyList; // Lists are supposed to be allocated on the stack to have their elements properly marked, which is not the case here - but this list has nothing to mark. SmallStrings smallStrings; - + NumericStrings numericStrings; + DateInstanceCache dateInstanceCache; + #if ENABLE(ASSEMBLER) ExecutableAllocator executableAllocator; #endif @@ -145,16 +169,34 @@ namespace JSC { HashSet<JSObject*> arrayVisitedElements; - ScopeNode* scopeNodeBeingReparsed; + CodeBlock* functionCodeBlockBeingReparsed; Stringifier* firstStringifierToMark; MarkStack markStack; + + double cachedUTCOffset; + DSTOffsetCache dstOffsetCache; + + UString cachedDateString; + double cachedDateStringValue; + + WeakRandom weakRandom; + +#ifndef NDEBUG + bool mainThreadOnly; +#endif + + void resetDateCache(); + + void startSampling(); + void stopSampling(); + void dumpSampleData(ExecState* exec); private: JSGlobalData(bool isShared, const VPtrSet&); static JSGlobalData*& sharedInstanceInternal(); void createNativeThunk(); }; - + } // namespace JSC #endif // JSGlobalData_h diff --git a/JavaScriptCore/runtime/JSGlobalObject.cpp b/JavaScriptCore/runtime/JSGlobalObject.cpp index a90f18f..cf3f1d1 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.cpp +++ b/JavaScriptCore/runtime/JSGlobalObject.cpp @@ -89,7 +89,7 @@ static inline void markIfNeeded(MarkStack& markStack, JSValue v) static inline void markIfNeeded(MarkStack& markStack, const RefPtr<Structure>& s) { if (s) - s->markAggregate(markStack); + markIfNeeded(markStack, s->storedPrototype()); } JSGlobalObject::~JSGlobalObject() @@ -112,8 +112,8 @@ JSGlobalObject::~JSGlobalObject() if (headObject == this) headObject = 0; - HashSet<ProgramCodeBlock*>::const_iterator end = codeBlocks().end(); - for (HashSet<ProgramCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it) + HashSet<GlobalCodeBlock*>::const_iterator end = codeBlocks().end(); + for (HashSet<GlobalCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it) (*it)->clearGlobalObject(); RegisterFile& registerFile = globalData()->interpreter->registerFile(); @@ -121,7 +121,7 @@ JSGlobalObject::~JSGlobalObject() registerFile.setGlobalObject(0); registerFile.setNumGlobals(0); } - delete d(); + d()->destructor(d()); } void JSGlobalObject::init(JSObject* thisValue) @@ -129,7 +129,7 @@ void JSGlobalObject::init(JSObject* thisValue) ASSERT(JSLock::currentThreadIsHoldingLock()); d()->globalData = Heap::heap(this)->globalData(); - d()->globalScopeChain = ScopeChain(this, d()->globalData.get(), thisValue); + d()->globalScopeChain = ScopeChain(this, d()->globalData.get(), this, thisValue); JSGlobalObject::globalExec()->init(0, 0, d()->globalScopeChain.node(), CallFrame::noCaller(), 0, 0, 0); @@ -175,18 +175,18 @@ void JSGlobalObject::putWithAttributes(ExecState* exec, const Identifier& proper } } -void JSGlobalObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunc) +void JSGlobalObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes) { PropertySlot slot; if (!symbolTableGet(propertyName, slot)) - JSVariableObject::defineGetter(exec, propertyName, getterFunc); + JSVariableObject::defineGetter(exec, propertyName, getterFunc, attributes); } -void JSGlobalObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunc) +void JSGlobalObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes) { PropertySlot slot; if (!symbolTableGet(propertyName, slot)) - JSVariableObject::defineSetter(exec, propertyName, setterFunc); + JSVariableObject::defineSetter(exec, propertyName, setterFunc, attributes); } static inline JSObject* lastInPrototypeChain(JSObject* object) @@ -258,7 +258,7 @@ void JSGlobalObject::reset(JSValue prototype) JSCell* objectConstructor = new (exec) ObjectConstructor(exec, ObjectConstructor::createStructure(d()->functionPrototype), d()->objectPrototype, d()->prototypeFunctionStructure.get()); JSCell* functionConstructor = new (exec) FunctionConstructor(exec, FunctionConstructor::createStructure(d()->functionPrototype), d()->functionPrototype); - JSCell* arrayConstructor = new (exec) ArrayConstructor(exec, ArrayConstructor::createStructure(d()->functionPrototype), d()->arrayPrototype); + JSCell* arrayConstructor = new (exec) ArrayConstructor(exec, ArrayConstructor::createStructure(d()->functionPrototype), d()->arrayPrototype, d()->prototypeFunctionStructure.get()); JSCell* stringConstructor = new (exec) StringConstructor(exec, StringConstructor::createStructure(d()->functionPrototype), d()->prototypeFunctionStructure.get(), d()->stringPrototype); JSCell* booleanConstructor = new (exec) BooleanConstructor(exec, BooleanConstructor::createStructure(d()->functionPrototype), d()->booleanPrototype); JSCell* numberConstructor = new (exec) NumberConstructor(exec, NumberConstructor::createStructure(d()->functionPrototype), d()->numberPrototype); @@ -361,8 +361,8 @@ void JSGlobalObject::markChildren(MarkStack& markStack) { JSVariableObject::markChildren(markStack); - HashSet<ProgramCodeBlock*>::const_iterator end = codeBlocks().end(); - for (HashSet<ProgramCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it) + HashSet<GlobalCodeBlock*>::const_iterator end = codeBlocks().end(); + for (HashSet<GlobalCodeBlock*>::const_iterator it = codeBlocks().begin(); it != end; ++it) (*it)->markAggregate(markStack); RegisterFile& registerFile = globalData()->interpreter->registerFile(); @@ -394,6 +394,21 @@ void JSGlobalObject::markChildren(MarkStack& markStack) markIfNeeded(markStack, d()->methodCallDummy); markIfNeeded(markStack, d()->errorStructure); + markIfNeeded(markStack, d()->argumentsStructure); + markIfNeeded(markStack, d()->arrayStructure); + markIfNeeded(markStack, d()->booleanObjectStructure); + markIfNeeded(markStack, d()->callbackConstructorStructure); + markIfNeeded(markStack, d()->callbackFunctionStructure); + markIfNeeded(markStack, d()->callbackObjectStructure); + markIfNeeded(markStack, d()->dateStructure); + markIfNeeded(markStack, d()->emptyObjectStructure); + markIfNeeded(markStack, d()->errorStructure); + markIfNeeded(markStack, d()->functionStructure); + markIfNeeded(markStack, d()->numberObjectStructure); + markIfNeeded(markStack, d()->prototypeFunctionStructure); + markIfNeeded(markStack, d()->regExpMatchesArrayStructure); + markIfNeeded(markStack, d()->regExpStructure); + markIfNeeded(markStack, d()->stringObjectStructure); // No need to mark the other structures, because their prototypes are all // guaranteed to be referenced elsewhere. @@ -448,11 +463,12 @@ void JSGlobalObject::copyGlobalsTo(RegisterFile& registerFile) void* JSGlobalObject::operator new(size_t size, JSGlobalData* globalData) { -#ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return globalData->heap.inlineAllocate(size); -#else return globalData->heap.allocate(size); -#endif +} + +void JSGlobalObject::destroyJSGlobalObjectData(void* jsGlobalObjectData) +{ + delete static_cast<JSGlobalObjectData*>(jsGlobalObjectData); } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSGlobalObject.h b/JavaScriptCore/runtime/JSGlobalObject.h index cda49bd..9e4ef49 100644 --- a/JavaScriptCore/runtime/JSGlobalObject.h +++ b/JavaScriptCore/runtime/JSGlobalObject.h @@ -22,6 +22,7 @@ #ifndef JSGlobalObject_h #define JSGlobalObject_h +#include "JSArray.h" #include "JSGlobalData.h" #include "JSVariableObject.h" #include "NativeFunctionWrapper.h" @@ -38,6 +39,7 @@ namespace JSC { class Debugger; class ErrorConstructor; class FunctionPrototype; + class GlobalCodeBlock; class GlobalEvalFunction; class NativeErrorConstructor; class ProgramCodeBlock; @@ -50,14 +52,22 @@ namespace JSC { struct HashTable; typedef Vector<ExecState*, 16> ExecStateStack; - + class JSGlobalObject : public JSVariableObject { protected: using JSVariableObject::JSVariableObjectData; struct JSGlobalObjectData : public JSVariableObjectData { - JSGlobalObjectData() + // We use an explicit destructor function pointer instead of a + // virtual destructor because we want to avoid adding a vtable + // pointer to this struct. Adding a vtable pointer would force the + // compiler to emit costly pointer fixup code when casting from + // JSVariableObjectData* to JSGlobalObjectData*. + typedef void (*Destructor)(void*); + + JSGlobalObjectData(Destructor destructor) : JSVariableObjectData(&symbolTable, 0) + , destructor(destructor) , registerArraySize(0) , globalScopeChain(NoScopeChain()) , regExpConstructor(0) @@ -83,10 +93,8 @@ namespace JSC { { } - virtual ~JSGlobalObjectData() - { - } - + Destructor destructor; + size_t registerArraySize; JSGlobalObject* next; @@ -144,20 +152,20 @@ namespace JSC { RefPtr<JSGlobalData> globalData; - HashSet<ProgramCodeBlock*> codeBlocks; + HashSet<GlobalCodeBlock*> codeBlocks; }; public: void* operator new(size_t, JSGlobalData*); explicit JSGlobalObject() - : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData) + : JSVariableObject(JSGlobalObject::createStructure(jsNull()), new JSGlobalObjectData(destroyJSGlobalObjectData)) { init(this); } protected: - JSGlobalObject(PassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue) + JSGlobalObject(NonNullPassRefPtr<Structure> structure, JSGlobalObjectData* data, JSObject* thisValue) : JSVariableObject(structure, data) { init(thisValue); @@ -169,12 +177,13 @@ namespace JSC { virtual void markChildren(MarkStack&); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual bool hasOwnPropertyForWrite(ExecState*, const Identifier&); virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); virtual void putWithAttributes(ExecState*, const Identifier& propertyName, JSValue value, unsigned attributes); - virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc); - virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc); + virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunc, unsigned attributes); + virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunc, unsigned attributes); // Linked list of all global objects that use the same JSGlobalData. JSGlobalObject*& head() { return d()->globalData->head; } @@ -246,7 +255,7 @@ namespace JSC { virtual bool isDynamicScope() const; - HashSet<ProgramCodeBlock*>& codeBlocks() { return d()->codeBlocks; } + HashSet<GlobalCodeBlock*>& codeBlocks() { return d()->codeBlocks; } void copyGlobalsFrom(RegisterFile&); void copyGlobalsTo(RegisterFile&); @@ -258,10 +267,13 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } protected: + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; + struct GlobalPropertyInfo { GlobalPropertyInfo(const Identifier& i, JSValue v, unsigned a) : identifier(i) @@ -277,6 +289,8 @@ namespace JSC { void addStaticGlobals(GlobalPropertyInfo*, int count); private: + static void destroyJSGlobalObjectData(void*); + // FIXME: Fold reset into init. void init(JSObject* thisValue); void reset(JSValue prototype); @@ -325,6 +339,13 @@ namespace JSC { return symbolTableGet(propertyName, slot); } + inline bool JSGlobalObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) + { + if (symbolTableGet(propertyName, descriptor)) + return true; + return JSVariableObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); + } + inline bool JSGlobalObject::hasOwnPropertyForWrite(ExecState* exec, const Identifier& propertyName) { PropertySlot slot; @@ -334,14 +355,6 @@ namespace JSC { return symbolTableGet(propertyName, slot, slotIsWriteable); } - inline JSGlobalObject* ScopeChainNode::globalObject() const - { - const ScopeChainNode* n = this; - while (n->next) - n = n->next; - return asGlobalObject(n->object); - } - inline JSValue Structure::prototypeForLookup(ExecState* exec) const { if (typeInfo().type() == ObjectType) @@ -396,13 +409,46 @@ namespace JSC { return globalData().dynamicGlobalObject; } + inline JSObject* constructEmptyObject(ExecState* exec) + { + return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); + } + + inline JSArray* constructEmptyArray(ExecState* exec) + { + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure()); + } + + inline JSArray* constructEmptyArray(ExecState* exec, unsigned initialLength) + { + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), initialLength); + } + + inline JSArray* constructArray(ExecState* exec, JSValue singleItemValue) + { + MarkedArgumentBuffer values; + values.append(singleItemValue); + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); + } + + inline JSArray* constructArray(ExecState* exec, const ArgList& values) + { + return new (exec) JSArray(exec->lexicalGlobalObject()->arrayStructure(), values); + } + class DynamicGlobalObjectScope : public Noncopyable { public: DynamicGlobalObjectScope(CallFrame* callFrame, JSGlobalObject* dynamicGlobalObject) : m_dynamicGlobalObjectSlot(callFrame->globalData().dynamicGlobalObject) , m_savedDynamicGlobalObject(m_dynamicGlobalObjectSlot) { - m_dynamicGlobalObjectSlot = dynamicGlobalObject; + if (!m_dynamicGlobalObjectSlot) { + m_dynamicGlobalObjectSlot = dynamicGlobalObject; + + // Reset the date cache between JS invocations to force the VM + // to observe time zone changes. + callFrame->globalData().resetDateCache(); + } } ~DynamicGlobalObjectScope() diff --git a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp index affb99c..dc32718 100644 --- a/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp +++ b/JavaScriptCore/runtime/JSGlobalObjectFunctions.cpp @@ -286,16 +286,12 @@ JSValue JSC_HOST_CALL globalFuncEval(ExecState* exec, JSObject* function, JSValu if (JSValue parsedObject = preparser.tryLiteralParse()) return parsedObject; - int errLine; - UString errMsg; + RefPtr<EvalExecutable> eval = EvalExecutable::create(exec, makeSource(s)); + JSObject* error = eval->compile(exec, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node()); + if (error) + return throwError(exec, error); - SourceCode source = makeSource(s); - RefPtr<EvalNode> evalNode = exec->globalData().parser->parse<EvalNode>(exec, exec->dynamicGlobalObject()->debugger(), source, &errLine, &errMsg); - - if (!evalNode) - return throwError(exec, SyntaxError, errMsg, errLine, source.provider()->asID(), NULL); - - return exec->interpreter()->execute(evalNode.get(), exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node(), exec->exceptionSlot()); + return exec->interpreter()->execute(eval.get(), exec, thisObject, static_cast<JSGlobalObject*>(unwrappedObject)->globalScopeChain().node(), exec->exceptionSlot()); } JSValue JSC_HOST_CALL globalFuncParseInt(ExecState* exec, JSObject*, JSValue, const ArgList& args) diff --git a/JavaScriptCore/runtime/JSNotAnObject.cpp b/JavaScriptCore/runtime/JSNotAnObject.cpp index a542a9f..c36dc10 100644 --- a/JavaScriptCore/runtime/JSNotAnObject.cpp +++ b/JavaScriptCore/runtime/JSNotAnObject.cpp @@ -93,6 +93,12 @@ bool JSNotAnObject::getOwnPropertySlot(ExecState* exec, unsigned, PropertySlot&) return false; } +bool JSNotAnObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier&, PropertyDescriptor&) +{ + ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); + return false; +} + void JSNotAnObject::put(ExecState* exec, const Identifier& , JSValue, PutPropertySlot&) { ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); @@ -115,7 +121,7 @@ bool JSNotAnObject::deleteProperty(ExecState* exec, unsigned) return false; } -void JSNotAnObject::getPropertyNames(ExecState* exec, PropertyNameArray&) +void JSNotAnObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray&) { ASSERT_UNUSED(exec, exec->hadException() && exec->exception() == m_exception); } diff --git a/JavaScriptCore/runtime/JSNotAnObject.h b/JavaScriptCore/runtime/JSNotAnObject.h index b65ff5f..a271c4e 100644 --- a/JavaScriptCore/runtime/JSNotAnObject.h +++ b/JavaScriptCore/runtime/JSNotAnObject.h @@ -62,10 +62,13 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } private: + + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSObject::StructureFlags; + // JSValue methods virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue&); @@ -80,6 +83,7 @@ namespace JSC { // JSObject methods virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual void put(ExecState*, unsigned propertyName, JSValue); @@ -87,7 +91,7 @@ namespace JSC { virtual bool deleteProperty(ExecState*, const Identifier& propertyName); virtual bool deleteProperty(ExecState*, unsigned propertyName); - virtual void getPropertyNames(ExecState*, PropertyNameArray&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&); JSNotAnObjectErrorStub* m_exception; }; diff --git a/JavaScriptCore/runtime/JSNumberCell.cpp b/JavaScriptCore/runtime/JSNumberCell.cpp index 0654da7..f1009b9 100644 --- a/JavaScriptCore/runtime/JSNumberCell.cpp +++ b/JavaScriptCore/runtime/JSNumberCell.cpp @@ -54,15 +54,11 @@ double JSNumberCell::toNumber(ExecState*) const UString JSNumberCell::toString(ExecState*) const { - if (m_value == 0.0) // +0.0 or -0.0 - return "0"; return UString::from(m_value); } UString JSNumberCell::toThisString(ExecState*) const { - if (m_value == 0.0) // +0.0 or -0.0 - return "0"; return UString::from(m_value); } diff --git a/JavaScriptCore/runtime/JSNumberCell.h b/JavaScriptCore/runtime/JSNumberCell.h index 04cccef..e9e2470 100644 --- a/JavaScriptCore/runtime/JSNumberCell.h +++ b/JavaScriptCore/runtime/JSNumberCell.h @@ -68,23 +68,15 @@ namespace JSC { void* operator new(size_t size, ExecState* exec) { - #ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return exec->heap()->inlineAllocateNumber(size); - #else return exec->heap()->allocateNumber(size); - #endif } void* operator new(size_t size, JSGlobalData* globalData) { - #ifdef JAVASCRIPTCORE_BUILDING_ALL_IN_ONE_FILE - return globalData->heap.inlineAllocateNumber(size); - #else return globalData->heap.allocateNumber(size); - #endif } - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, NeedsThisConversion)); } + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(NumberType, OverridesGetOwnPropertySlot | NeedsThisConversion)); } private: JSNumberCell(JSGlobalData* globalData, double value) @@ -117,6 +109,11 @@ namespace JSC { return static_cast<JSNumberCell*>(v.asCell()); } + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState* exec, double d) + { + *this = jsNumberCell(exec, d); + } + inline JSValue::JSValue(ExecState* exec, double d) { JSValue v = JSImmediate::from(d); @@ -201,6 +198,11 @@ namespace JSC { #endif // USE(JSVALUE32) #if USE(JSVALUE64) + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState*, double d) + { + *this = JSImmediate::fromNumberOutsideIntegerRange(d); + } + inline JSValue::JSValue(ExecState*, double d) { JSValue v = JSImmediate::from(d); diff --git a/JavaScriptCore/runtime/JSONObject.cpp b/JavaScriptCore/runtime/JSONObject.cpp index d643808..cc7f6d9 100644 --- a/JavaScriptCore/runtime/JSONObject.cpp +++ b/JavaScriptCore/runtime/JSONObject.cpp @@ -70,7 +70,23 @@ public: void markAggregate(MarkStack&); private: - typedef UString StringBuilder; + class StringBuilder : public Vector<UChar> { + public: + using Vector<UChar>::append; + + inline void append(const char* str) + { + size_t len = strlen(str); + reserveCapacity(size() + len); + for (size_t i = 0; i < len; i++) + Vector<UChar>::append(str[i]); + } + + inline void append(const UString& str) + { + append(str.data(), str.size()); + } + }; class Holder { public: @@ -120,38 +136,47 @@ private: // ------------------------------ helper functions -------------------------------- -static inline JSValue unwrapBoxedPrimitive(JSValue value) +static inline JSValue unwrapBoxedPrimitive(ExecState* exec, JSValue value) { if (!value.isObject()) return value; - if (!asObject(value)->inherits(&NumberObject::info) && !asObject(value)->inherits(&StringObject::info) && !asObject(value)->inherits(&BooleanObject::info)) - return value; - return static_cast<JSWrapperObject*>(asObject(value))->internalValue(); + JSObject* object = asObject(value); + if (object->inherits(&NumberObject::info)) + return jsNumber(exec, object->toNumber(exec)); + if (object->inherits(&StringObject::info)) + return jsString(exec, object->toString(exec)); + if (object->inherits(&BooleanObject::info)) + return object->toPrimitive(exec); + return value; } -static inline UString gap(JSValue space) +static inline UString gap(ExecState* exec, JSValue space) { - space = unwrapBoxedPrimitive(space); + const int maxGapLength = 10; + space = unwrapBoxedPrimitive(exec, space); // If the space value is a number, create a gap string with that number of spaces. double spaceCount; if (space.getNumber(spaceCount)) { - const int maxSpaceCount = 100; int count; - if (spaceCount > maxSpaceCount) - count = maxSpaceCount; + if (spaceCount > maxGapLength) + count = maxGapLength; else if (!(spaceCount > 0)) count = 0; else count = static_cast<int>(spaceCount); - UChar spaces[maxSpaceCount]; + UChar spaces[maxGapLength]; for (int i = 0; i < count; ++i) spaces[i] = ' '; return UString(spaces, count); } // If the space value is a string, use it as the gap string, otherwise use no gap string. - return space.getString(); + UString spaces = space.getString(exec); + if (spaces.size() > maxGapLength) { + spaces = spaces.substr(0, maxGapLength); + } + return spaces; } // ------------------------------ PropertyNameForFunctionCall -------------------------------- @@ -187,7 +212,7 @@ Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space) , m_usingArrayReplacer(false) , m_arrayReplacerPropertyNames(exec) , m_replacerCallType(CallTypeNone) - , m_gap(gap(space)) + , m_gap(gap(exec, space)) { exec->globalData().firstStringifierToMark = this; @@ -202,12 +227,27 @@ Stringifier::Stringifier(ExecState* exec, JSValue replacer, JSValue space) JSValue name = array->get(exec, i); if (exec->hadException()) break; + UString propertyName; - if (!name.getString(propertyName)) + if (name.getString(exec, propertyName)) { + m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName)); continue; - if (exec->hadException()) - return; - m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName)); + } + + double value = 0; + if (name.getNumber(value)) { + m_arrayReplacerPropertyNames.add(Identifier::from(exec, value)); + continue; + } + + if (name.isObject()) { + if (!asObject(name)->inherits(&NumberObject::info) && !asObject(name)->inherits(&StringObject::info)) + continue; + propertyName = name.toString(exec); + if (exec->hadException()) + break; + m_arrayReplacerPropertyNames.add(Identifier(exec, propertyName)); + } } return; } @@ -245,7 +285,9 @@ JSValue Stringifier::stringify(JSValue value) if (m_exec->hadException()) return jsNull(); - return jsString(m_exec, result); + result.shrinkToFit(); + size_t length = result.size(); + return jsString(m_exec, UString(result.releaseBuffer(), length, false)); } void Stringifier::appendQuotedString(StringBuilder& builder, const UString& value) @@ -354,7 +396,10 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& return StringifySucceeded; } - value = unwrapBoxedPrimitive(value); + value = unwrapBoxedPrimitive(m_exec, value); + + if (m_exec->hadException()) + return StringifyFailed; if (value.isBoolean()) { builder.append(value.getBoolean() ? "true" : "false"); @@ -362,7 +407,7 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& } UString stringValue; - if (value.getString(stringValue)) { + if (value.getString(m_exec, stringValue)) { appendQuotedString(builder, stringValue); return StringifySucceeded; } @@ -381,6 +426,15 @@ Stringifier::StringifyResult Stringifier::appendStringifiedValue(StringBuilder& JSObject* object = asObject(value); + CallData callData; + if (object->getCallData(callData) != CallTypeNone) { + if (holder->inherits(&JSArray::info)) { + builder.append("null"); + return StringifySucceeded; + } + return StringifyFailedDueToUndefinedValue; + } + // Handle cycle detection, and put the holder on the stack. if (!m_holderCycleDetector.add(object).second) { throwError(m_exec, TypeError, "JSON.stringify cannot serialize cyclic structures."); @@ -550,7 +604,7 @@ bool Stringifier::Holder::appendNextProperty(Stringifier& stringifier, StringBui // This only occurs when get an undefined value for an object property. // In this case we don't want the separator and property name that we // already appended, so roll back. - builder = builder.substr(0, rollBackPoint); + builder.resize(rollBackPoint); break; } @@ -572,13 +626,12 @@ const ClassInfo JSONObject::info = { "JSON", 0, 0, ExecState::jsonTable }; bool JSONObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { - const HashEntry* entry = ExecState::jsonTable(exec)->entry(exec, propertyName); - if (!entry) - return JSObject::getOwnPropertySlot(exec, propertyName, slot); + return getStaticFunctionSlot<JSObject>(exec, ExecState::jsonTable(exec), this, propertyName, slot); +} - ASSERT(entry->attributes() & Function); - setUpStaticFunctionSlot(exec, entry, this, propertyName, slot); - return true; +bool JSONObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticFunctionDescriptor<JSObject>(exec, ExecState::jsonTable(exec), this, propertyName, descriptor); } void JSONObject::markStringifiers(MarkStack& markStack, Stringifier* stringifier) @@ -597,11 +650,11 @@ public: } JSValue walk(JSValue unfiltered); private: - JSValue callReviver(JSValue property, JSValue unfiltered) + JSValue callReviver(JSObject* thisObj, JSValue property, JSValue unfiltered) { JSValue args[] = { property, unfiltered }; ArgList argList(args, 2); - return call(m_exec, m_function, m_callType, m_callData, jsNull(), argList); + return call(m_exec, m_function, m_callType, m_callData, thisObj, argList); } friend class Holder; @@ -611,7 +664,10 @@ private: CallType m_callType; CallData m_callData; }; - + +// We clamp recursion well beyond anything reasonable, but we also have a timeout check +// to guard against "infinite" execution by inserting arbitrarily large objects. +static const unsigned maximumFilterRecursion = 40000; enum WalkerState { StateUnknown, ArrayStartState, ArrayStartVisitMember, ArrayEndVisitMember, ObjectStartState, ObjectStartVisitMember, ObjectEndVisitMember }; NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) @@ -625,12 +681,21 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) WalkerState state = StateUnknown; JSValue inValue = unfiltered; JSValue outValue = jsNull(); + + TimeoutChecker localTimeoutChecker(m_exec->globalData().timeoutChecker); + localTimeoutChecker.reset(); + unsigned tickCount = localTimeoutChecker.ticksUntilNextCheck(); while (1) { switch (state) { arrayStartState: case ArrayStartState: { ASSERT(inValue.isObject()); - ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue))); + ASSERT(isJSArray(&m_exec->globalData(), asObject(inValue)) || asObject(inValue)->inherits(&JSArray::info)); + if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) { + m_exec->setException(createStackOverflowError(m_exec)); + return jsUndefined(); + } + JSArray* array = asArray(inValue); arrayStack.append(array); indexStack.append(0); @@ -638,6 +703,14 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) } arrayStartVisitMember: case ArrayStartVisitMember: { + if (!--tickCount) { + if (localTimeoutChecker.didTimeOut(m_exec)) { + m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); + return jsUndefined(); + } + tickCount = localTimeoutChecker.ticksUntilNextCheck(); + } + JSArray* array = arrayStack.last(); uint32_t index = indexStack.last(); if (index == array->length()) { @@ -646,7 +719,16 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) indexStack.removeLast(); break; } - inValue = array->getIndex(index); + if (isJSArray(&m_exec->globalData(), array) && array->canGetIndex(index)) + inValue = array->getIndex(index); + else { + PropertySlot slot; + if (array->getOwnPropertySlot(m_exec, index, slot)) + inValue = slot.getValue(m_exec, index); + else + inValue = jsUndefined(); + } + if (inValue.isObject()) { stateStack.append(ArrayEndVisitMember); goto stateUnknown; @@ -656,7 +738,15 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) } case ArrayEndVisitMember: { JSArray* array = arrayStack.last(); - array->setIndex(indexStack.last(), callReviver(jsString(m_exec, UString::from(indexStack.last())), outValue)); + JSValue filteredValue = callReviver(array, jsString(m_exec, UString::from(indexStack.last())), outValue); + if (filteredValue.isUndefined()) + array->deleteProperty(m_exec, indexStack.last()); + else { + if (isJSArray(&m_exec->globalData(), array) && array->canSetIndex(indexStack.last())) + array->setIndex(indexStack.last(), filteredValue); + else + array->put(m_exec, indexStack.last(), filteredValue); + } if (m_exec->hadException()) return jsNull(); indexStack.last()++; @@ -665,7 +755,12 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) objectStartState: case ObjectStartState: { ASSERT(inValue.isObject()); - ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue))); + ASSERT(!isJSArray(&m_exec->globalData(), asObject(inValue)) && !asObject(inValue)->inherits(&JSArray::info)); + if (objectStack.size() + arrayStack.size() > maximumFilterRecursion) { + m_exec->setException(createStackOverflowError(m_exec)); + return jsUndefined(); + } + JSObject* object = asObject(inValue); objectStack.append(object); indexStack.append(0); @@ -675,6 +770,14 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) } objectStartVisitMember: case ObjectStartVisitMember: { + if (!--tickCount) { + if (localTimeoutChecker.didTimeOut(m_exec)) { + m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); + return jsUndefined(); + } + tickCount = localTimeoutChecker.ticksUntilNextCheck(); + } + JSObject* object = objectStack.last(); uint32_t index = indexStack.last(); PropertyNameArray& properties = propertyStack.last(); @@ -686,9 +789,15 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) break; } PropertySlot slot; - object->getOwnPropertySlot(m_exec, properties[index], slot); - inValue = slot.getValue(m_exec, properties[index]); - ASSERT(!m_exec->hadException()); + if (object->getOwnPropertySlot(m_exec, properties[index], slot)) + inValue = slot.getValue(m_exec, properties[index]); + else + inValue = jsUndefined(); + + // The holder may be modified by the reviver function so any lookup may throw + if (m_exec->hadException()) + return jsNull(); + if (inValue.isObject()) { stateStack.append(ObjectEndVisitMember); goto stateUnknown; @@ -700,7 +809,11 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) JSObject* object = objectStack.last(); Identifier prop = propertyStack.last()[indexStack.last()]; PutPropertySlot slot; - object->put(m_exec, prop, callReviver(jsString(m_exec, prop.ustring()), outValue), slot); + JSValue filteredValue = callReviver(object, jsString(m_exec, prop.ustring()), outValue); + if (filteredValue.isUndefined()) + object->deleteProperty(m_exec, prop); + else + object->put(m_exec, prop, filteredValue, slot); if (m_exec->hadException()) return jsNull(); indexStack.last()++; @@ -712,16 +825,29 @@ NEVER_INLINE JSValue Walker::walk(JSValue unfiltered) outValue = inValue; break; } - if (isJSArray(&m_exec->globalData(), asObject(inValue))) + JSObject* object = asObject(inValue); + if (isJSArray(&m_exec->globalData(), object) || object->inherits(&JSArray::info)) goto arrayStartState; goto objectStartState; } if (stateStack.isEmpty()) break; + state = stateStack.last(); stateStack.removeLast(); + + if (!--tickCount) { + if (localTimeoutChecker.didTimeOut(m_exec)) { + m_exec->setException(createInterruptedExecutionException(&m_exec->globalData())); + return jsUndefined(); + } + tickCount = localTimeoutChecker.ticksUntilNextCheck(); + } } - return callReviver(jsEmptyString(m_exec), outValue); + JSObject* finalHolder = constructEmptyObject(m_exec); + PutPropertySlot slot; + finalHolder->put(m_exec, m_exec->globalData().propertyNames->emptyIdentifier, outValue, slot); + return callReviver(finalHolder, jsEmptyString(m_exec), outValue); } // ECMA-262 v5 15.12.2 diff --git a/JavaScriptCore/runtime/JSONObject.h b/JavaScriptCore/runtime/JSONObject.h index faca7c7..ec3fa40 100644 --- a/JavaScriptCore/runtime/JSONObject.h +++ b/JavaScriptCore/runtime/JSONObject.h @@ -34,20 +34,24 @@ namespace JSC { class JSONObject : public JSObject { public: - JSONObject(PassRefPtr<Structure> structure) + JSONObject(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { } static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } static void markStringifiers(MarkStack&, Stringifier*); + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; + private: virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; diff --git a/JavaScriptCore/runtime/JSObject.cpp b/JavaScriptCore/runtime/JSObject.cpp index 419dfe9..ed9fdc2 100644 --- a/JavaScriptCore/runtime/JSObject.cpp +++ b/JavaScriptCore/runtime/JSObject.cpp @@ -30,6 +30,7 @@ #include "JSGlobalObject.h" #include "NativeErrorConstructor.h" #include "ObjectPrototype.h" +#include "PropertyDescriptor.h" #include "PropertyNameArray.h" #include "Lookup.h" #include "Nodes.h" @@ -37,43 +38,41 @@ #include <math.h> #include <wtf/Assertions.h> -#define JSOBJECT_MARK_TRACING 0 - -#if JSOBJECT_MARK_TRACING - -#define JSOBJECT_MARK_BEGIN() \ - static int markStackDepth = 0; \ - for (int i = 0; i < markStackDepth; i++) \ - putchar('-'); \ - printf("%s (%p)\n", className().UTF8String().c_str(), this); \ - markStackDepth++; \ - -#define JSOBJECT_MARK_END() \ - markStackDepth--; - -#else // JSOBJECT_MARK_TRACING - -#define JSOBJECT_MARK_BEGIN() -#define JSOBJECT_MARK_END() - -#endif // JSOBJECT_MARK_TRACING - namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSObject); +static inline void getEnumerablePropertyNames(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames) +{ + // Add properties from the static hashtables of properties + for (; classInfo; classInfo = classInfo->parentClass) { + const HashTable* table = classInfo->propHashTable(exec); + if (!table) + continue; + table->initializeIfNeeded(exec); + ASSERT(table->table); + + int hashSizeMask = table->compactSize - 1; + const HashEntry* entry = table->table; + for (int i = 0; i <= hashSizeMask; ++i, ++entry) { + if (entry->key() && !(entry->attributes() & DontEnum)) + propertyNames.add(entry->key()); + } + } +} + void JSObject::markChildren(MarkStack& markStack) { - JSOBJECT_MARK_BEGIN(); - - JSCell::markChildren(markStack); - m_structure->markAggregate(markStack); +#ifndef NDEBUG + bool wasCheckingForDefaultMarkViolation = markStack.m_isCheckingForDefaultMarkViolation; + markStack.m_isCheckingForDefaultMarkViolation = false; +#endif - PropertyStorage storage = propertyStorage(); - size_t storageSize = m_structure->propertyStorageSize(); - markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize); + markChildrenDirect(markStack); - JSOBJECT_MARK_END(); +#ifndef NDEBUG + markStack.m_isCheckingForDefaultMarkViolation = wasCheckingForDefaultMarkViolation; +#endif } UString JSObject::className() const @@ -295,7 +294,7 @@ const HashEntry* JSObject::findPropertyHashEntry(ExecState* exec, const Identifi return 0; } -void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction) +void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes) { JSValue object = getDirect(propertyName); if (object && object.isGetterSetter()) { @@ -306,7 +305,7 @@ void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSO PutPropertySlot slot; GetterSetter* getterSetter = new (exec) GetterSetter(exec); - putDirectInternal(exec->globalData(), propertyName, getterSetter, Getter, true, slot); + putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Getter, true, slot); // putDirect will change our Structure if we add a new property. For // getters and setters, though, we also need to change our Structure @@ -322,7 +321,7 @@ void JSObject::defineGetter(ExecState* exec, const Identifier& propertyName, JSO getterSetter->setGetter(getterFunction); } -void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction) +void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes) { JSValue object = getDirect(propertyName); if (object && object.isGetterSetter()) { @@ -333,7 +332,7 @@ void JSObject::defineSetter(ExecState* exec, const Identifier& propertyName, JSO PutPropertySlot slot; GetterSetter* getterSetter = new (exec) GetterSetter(exec); - putDirectInternal(exec->globalData(), propertyName, getterSetter, Setter, true, slot); + putDirectInternal(exec->globalData(), propertyName, getterSetter, attributes | Setter, true, slot); // putDirect will change our Structure if we add a new property. For // getters and setters, though, we also need to change our Structure @@ -407,26 +406,10 @@ bool JSObject::hasInstance(ExecState* exec, JSValue value, JSValue proto) bool JSObject::propertyIsEnumerable(ExecState* exec, const Identifier& propertyName) const { - unsigned attributes; - if (!getPropertyAttributes(exec, propertyName, attributes)) + PropertyDescriptor descriptor; + if (!const_cast<JSObject*>(this)->getOwnPropertyDescriptor(exec, propertyName, descriptor)) return false; - return !(attributes & DontEnum); -} - -bool JSObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const -{ - JSCell* specificValue; - if (m_structure->get(propertyName, attributes, specificValue) != WTF::notFound) - return true; - - // Look in the static hashtable of properties - const HashEntry* entry = findPropertyHashEntry(exec, propertyName); - if (entry) { - attributes = entry->attributes(); - return true; - } - - return false; + return descriptor.enumerable(); } bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyName, JSCell*& specificValue) const @@ -444,7 +427,29 @@ bool JSObject::getPropertySpecificValue(ExecState*, const Identifier& propertyNa void JSObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { - m_structure->getEnumerablePropertyNames(exec, propertyNames, this); + getOwnPropertyNames(exec, propertyNames); + + if (prototype().isNull()) + return; + + JSObject* prototype = asObject(this->prototype()); + while(1) { + if (prototype->structure()->typeInfo().overridesGetPropertyNames()) { + prototype->getPropertyNames(exec, propertyNames); + break; + } + prototype->getOwnPropertyNames(exec, propertyNames); + JSValue nextProto = prototype->prototype(); + if (nextProto.isNull()) + break; + prototype = asObject(nextProto); + } +} + +void JSObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +{ + m_structure->getEnumerablePropertyNames(propertyNames); + getEnumerablePropertyNames(exec, classInfo(), propertyNames); } bool JSObject::toBoolean(ExecState*) const @@ -486,7 +491,7 @@ JSObject* JSObject::unwrappedObject() void JSObject::removeDirect(const Identifier& propertyName) { size_t offset; - if (m_structure->isDictionary()) { + if (m_structure->isUncacheableDictionary()) { offset = m_structure->removePropertyWithoutTransition(propertyName); if (offset != WTF::notFound) putDirectOffset(offset, jsUndefined()); @@ -501,12 +506,12 @@ void JSObject::removeDirect(const Identifier& propertyName) void JSObject::putDirectFunction(ExecState* exec, InternalFunction* function, unsigned attr) { - putDirectFunction(Identifier(exec, function->name(&exec->globalData())), function, attr); + putDirectFunction(Identifier(exec, function->name(exec)), function, attr); } void JSObject::putDirectFunctionWithoutTransition(ExecState* exec, InternalFunction* function, unsigned attr) { - putDirectFunctionWithoutTransition(Identifier(exec, function->name(&exec->globalData())), function, attr); + putDirectFunctionWithoutTransition(Identifier(exec, function->name(exec)), function, attr); } NEVER_INLINE void JSObject::fillGetterPropertySlot(PropertySlot& slot, JSValue* location) @@ -528,9 +533,154 @@ void JSObject::allocatePropertyStorage(size_t oldSize, size_t newSize) allocatePropertyStorageInline(oldSize, newSize); } -JSObject* constructEmptyObject(ExecState* exec) +bool JSObject::getOwnPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + unsigned attributes = 0; + JSCell* cell = 0; + size_t offset = m_structure->get(propertyName, attributes, cell); + if (offset == WTF::notFound) + return false; + descriptor.setDescriptor(getDirectOffset(offset), attributes); + return true; +} + +bool JSObject::getPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { - return new (exec) JSObject(exec->lexicalGlobalObject()->emptyObjectStructure()); + JSObject* object = this; + while (true) { + if (object->getOwnPropertyDescriptor(exec, propertyName, descriptor)) + return true; + JSValue prototype = object->prototype(); + if (!prototype.isObject()) + return false; + object = asObject(prototype); + } +} + +static bool putDescriptor(ExecState* exec, JSObject* target, const Identifier& propertyName, PropertyDescriptor& descriptor, unsigned attributes, JSValue oldValue) +{ + if (descriptor.isGenericDescriptor() || descriptor.isDataDescriptor()) { + target->putWithAttributes(exec, propertyName, descriptor.value() ? descriptor.value() : oldValue, attributes & ~(Getter | Setter)); + return true; + } + attributes &= ~ReadOnly; + if (descriptor.getter() && descriptor.getter().isObject()) + target->defineGetter(exec, propertyName, asObject(descriptor.getter()), attributes); + if (exec->hadException()) + return false; + if (descriptor.setter() && descriptor.setter().isObject()) + target->defineSetter(exec, propertyName, asObject(descriptor.setter()), attributes); + return !exec->hadException(); +} + +bool JSObject::defineOwnProperty(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor, bool throwException) +{ + // If we have a new property we can just put it on normally + PropertyDescriptor current; + if (!getOwnPropertyDescriptor(exec, propertyName, current)) + return putDescriptor(exec, this, propertyName, descriptor, descriptor.attributes(), jsUndefined()); + + if (descriptor.isEmpty()) + return true; + + if (current.equalTo(exec, descriptor)) + return true; + + // Filter out invalid changes + if (!current.configurable()) { + if (descriptor.configurable()) { + if (throwException) + throwError(exec, TypeError, "Attempting to configurable attribute of unconfigurable property."); + return false; + } + if (descriptor.enumerablePresent() && descriptor.enumerable() != current.enumerable()) { + if (throwException) + throwError(exec, TypeError, "Attempting to change enumerable attribute of unconfigurable property."); + return false; + } + } + + // A generic descriptor is simply changing the attributes of an existing property + if (descriptor.isGenericDescriptor()) { + if (!current.attributesEqual(descriptor)) { + deleteProperty(exec, propertyName); + putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value()); + } + return true; + } + + // Changing between a normal property or an accessor property + if (descriptor.isDataDescriptor() != current.isDataDescriptor()) { + if (!current.configurable()) { + if (throwException) + throwError(exec, TypeError, "Attempting to change access mechanism for an unconfigurable property."); + return false; + } + deleteProperty(exec, propertyName); + return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value() ? current.value() : jsUndefined()); + } + + // Changing the value and attributes of an existing property + if (descriptor.isDataDescriptor()) { + if (!current.configurable()) { + if (!current.writable() && descriptor.writable()) { + if (throwException) + throwError(exec, TypeError, "Attempting to change writable attribute of unconfigurable property."); + return false; + } + if (!current.writable()) { + if (descriptor.value() || !JSValue::strictEqual(exec, current.value(), descriptor.value())) { + if (throwException) + throwError(exec, TypeError, "Attempting to change value of a readonly property."); + return false; + } + } + } else if (current.attributesEqual(descriptor)) { + if (!descriptor.value()) + return true; + PutPropertySlot slot; + put(exec, propertyName, descriptor.value(), slot); + if (exec->hadException()) + return false; + return true; + } + deleteProperty(exec, propertyName); + return putDescriptor(exec, this, propertyName, descriptor, current.attributesWithOverride(descriptor), current.value()); + } + + // Changing the accessor functions of an existing accessor property + ASSERT(descriptor.isAccessorDescriptor()); + if (!current.configurable()) { + if (descriptor.setterPresent() && !(current.setter() && JSValue::strictEqual(exec, current.setter(), descriptor.setter()))) { + if (throwException) + throwError(exec, TypeError, "Attempting to change the setter of an unconfigurable property."); + return false; + } + if (descriptor.getterPresent() && !(current.getter() && JSValue::strictEqual(exec, current.getter(), descriptor.getter()))) { + if (throwException) + throwError(exec, TypeError, "Attempting to change the getter of an unconfigurable property."); + return false; + } + } + JSValue accessor = getDirect(propertyName); + if (!accessor) + return false; + GetterSetter* getterSetter = asGetterSetter(accessor); + if (current.attributesEqual(descriptor)) { + if (descriptor.setter()) + getterSetter->setSetter(asObject(descriptor.setter())); + if (descriptor.getter()) + getterSetter->setGetter(asObject(descriptor.getter())); + return true; + } + deleteProperty(exec, propertyName); + unsigned attrs = current.attributesWithOverride(descriptor); + if (descriptor.setter()) + attrs |= Setter; + if (descriptor.getter()) + attrs |= Getter; + putDirect(propertyName, getterSetter, attrs); + return true; } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSObject.h b/JavaScriptCore/runtime/JSObject.h index decd5e9..a5da267 100644 --- a/JavaScriptCore/runtime/JSObject.h +++ b/JavaScriptCore/runtime/JSObject.h @@ -27,7 +27,9 @@ #include "ClassInfo.h" #include "CommonIdentifiers.h" #include "CallFrame.h" +#include "JSCell.h" #include "JSNumberCell.h" +#include "MarkStack.h" #include "PropertySlot.h" #include "PutPropertySlot.h" #include "ScopeChain.h" @@ -46,6 +48,7 @@ namespace JSC { class HashEntry; class InternalFunction; + class PropertyDescriptor; class PropertyNameArray; class Structure; struct HashTable; @@ -71,20 +74,19 @@ namespace JSC { friend class JSCell; public: - explicit JSObject(PassRefPtr<Structure>); + explicit JSObject(NonNullPassRefPtr<Structure>); virtual void markChildren(MarkStack&); + ALWAYS_INLINE void markChildrenDirect(MarkStack& markStack); // The inline virtual destructor cannot be the first virtual function declared // in the class as it results in the vtable being generated as a weak symbol virtual ~JSObject(); - bool inherits(const ClassInfo* classInfo) const { return JSCell::isObject(classInfo); } - JSValue prototype() const; void setPrototype(JSValue prototype); - void setStructure(PassRefPtr<Structure>); + void setStructure(NonNullPassRefPtr<Structure>); Structure* inheritorID(); virtual UString className() const; @@ -94,9 +96,11 @@ namespace JSC { bool getPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); bool getPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + bool getPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState*, const Identifier& propertyName, JSValue value, PutPropertySlot&); virtual void put(ExecState*, unsigned propertyName, JSValue value); @@ -119,6 +123,7 @@ namespace JSC { virtual bool hasInstance(ExecState*, JSValue, JSValue prototypeProperty); virtual void getPropertyNames(ExecState*, PropertyNameArray&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&); virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType = NoPreference) const; virtual bool getPrimitiveNumber(ExecState*, double& number, JSValue& value); @@ -130,7 +135,6 @@ namespace JSC { virtual JSObject* toThisObject(ExecState*) const; virtual JSObject* unwrappedObject(); - virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; bool getPropertySpecificValue(ExecState* exec, const Identifier& propertyName, JSCell*& specificFunction) const; // This get function only looks at the property map. @@ -181,10 +185,11 @@ namespace JSC { void fillGetterPropertySlot(PropertySlot&, JSValue* location); - virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction); - virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction); + virtual void defineGetter(ExecState*, const Identifier& propertyName, JSObject* getterFunction, unsigned attributes = 0); + virtual void defineSetter(ExecState*, const Identifier& propertyName, JSObject* setterFunction, unsigned attributes = 0); virtual JSValue lookupGetter(ExecState*, const Identifier& propertyName); virtual JSValue lookupSetter(ExecState*, const Identifier& propertyName); + virtual bool defineOwnProperty(ExecState*, const Identifier& propertyName, PropertyDescriptor&, bool shouldThrow); virtual bool isGlobalObject() const { return false; } virtual bool isVariableObject() const { return false; } @@ -196,15 +201,45 @@ namespace JSC { void allocatePropertyStorageInline(size_t oldSize, size_t newSize); bool isUsingInlineStorage() const { return m_structure->isUsingInlineStorage(); } - static const size_t inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3; - static const size_t nonInlineBaseStorageCapacity = 16; + static const unsigned inlineStorageCapacity = sizeof(EncodedJSValue) == 2 * sizeof(void*) ? 4 : 3; + static const unsigned nonInlineBaseStorageCapacity = 16; static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, HasStandardGetOwnPropertySlot)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); + } + + void flattenDictionaryObject() + { + m_structure->flattenDictionaryStructure(this); + } + + protected: + static const unsigned StructureFlags = 0; + + void addAnonymousSlots(unsigned count); + void putAnonymousValue(unsigned index, JSValue value) + { + *locationForOffset(index) = value; + } + JSValue getAnonymousValue(unsigned index) + { + return *locationForOffset(index); } private: + // Nobody should ever ask any of these questions on something already known to be a JSObject. + using JSCell::isAPIValueWrapper; + using JSCell::isGetterSetter; + using JSCell::toObject; + void getObject(); + void getString(ExecState* exec); + void isObject(); + void isString(); +#if USE(JSVALUE32) + void isNumber(); +#endif + ConstPropertyStorage propertyStorage() const { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } PropertyStorage propertyStorage() { return (isUsingInlineStorage() ? m_inlineStorage : m_externalStorage); } @@ -235,18 +270,20 @@ namespace JSC { RefPtr<Structure> m_inheritorID; }; -JSObject* constructEmptyObject(ExecState*); +inline JSObject* asObject(JSCell* cell) +{ + ASSERT(cell->isObject()); + return static_cast<JSObject*>(cell); +} inline JSObject* asObject(JSValue value) { - ASSERT(asCell(value)->isObject()); - return static_cast<JSObject*>(asCell(value)); + return asObject(value.asCell()); } -inline JSObject::JSObject(PassRefPtr<Structure> structure) +inline JSObject::JSObject(NonNullPassRefPtr<Structure> structure) : JSCell(structure.releaseRef()) // ~JSObject balances this ref() { - ASSERT(m_structure); ASSERT(m_structure->propertyStorageCapacity() == inlineStorageCapacity); ASSERT(m_structure->isEmpty()); ASSERT(prototype().isNull() || Heap::heap(this) == Heap::heap(prototype())); @@ -275,7 +312,7 @@ inline void JSObject::setPrototype(JSValue prototype) setStructure(newStructure.release()); } -inline void JSObject::setStructure(PassRefPtr<Structure> structure) +inline void JSObject::setStructure(NonNullPassRefPtr<Structure> structure) { m_structure->deref(); m_structure = structure.releaseRef(); // ~JSObject balances this ref() @@ -293,7 +330,7 @@ inline bool Structure::isUsingInlineStorage() const return (propertyStorageCapacity() == JSObject::inlineStorageCapacity); } -inline bool JSCell::isObject(const ClassInfo* info) const +inline bool JSCell::inherits(const ClassInfo* info) const { for (const ClassInfo* ci = classInfo(); ci; ci = ci->parentClass) { if (ci == info) @@ -302,10 +339,10 @@ inline bool JSCell::isObject(const ClassInfo* info) const return false; } -// this method is here to be after the inline declaration of JSCell::isObject -inline bool JSValue::isObject(const ClassInfo* classInfo) const +// this method is here to be after the inline declaration of JSCell::inherits +inline bool JSValue::inherits(const ClassInfo* classInfo) const { - return isCell() && asCell()->isObject(classInfo); + return isCell() && asCell()->inherits(classInfo); } ALWAYS_INLINE bool JSObject::inlineGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) @@ -337,7 +374,7 @@ ALWAYS_INLINE bool JSObject::getOwnPropertySlot(ExecState* exec, const Identifie ALWAYS_INLINE bool JSCell::fastGetOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { - if (structure()->typeInfo().hasStandardGetOwnPropertySlot()) + if (!structure()->typeInfo().overridesGetOwnPropertySlot()) return asObject(this)->inlineGetOwnPropertySlot(exec, propertyName, slot); return getOwnPropertySlot(exec, propertyName, slot); } @@ -454,7 +491,18 @@ inline void JSObject::putDirectInternal(const Identifier& propertyName, JSValue return; } + // If we have a specific function, we may have got to this point if there is + // already a transition with the correct property name and attributes, but + // specialized to a different function. In this case we just want to give up + // and despecialize the transition. + // In this case we clear the value of specificFunction which will result + // in us adding a non-specific transition, and any subsequent lookup in + // Structure::addPropertyTransitionToExistingStructure will just use that. + if (specificFunction && m_structure->hasTransition(propertyName, attributes)) + specificFunction = 0; + RefPtr<Structure> structure = Structure::addPropertyTransition(m_structure, propertyName, attributes, specificFunction, offset); + if (currentCapacity != structure->propertyStorageCapacity()) allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); @@ -480,6 +528,17 @@ inline void JSObject::putDirectInternal(JSGlobalData& globalData, const Identifi putDirectInternal(propertyName, value, attributes, false, slot, getJSFunction(globalData, value)); } +inline void JSObject::addAnonymousSlots(unsigned count) +{ + size_t currentCapacity = m_structure->propertyStorageCapacity(); + RefPtr<Structure> structure = Structure::addAnonymousSlotsTransition(m_structure, count); + + if (currentCapacity != structure->propertyStorageCapacity()) + allocatePropertyStorage(currentCapacity, structure->propertyStorageCapacity()); + + setStructure(structure.release()); +} + inline void JSObject::putDirect(const Identifier& propertyName, JSValue value, unsigned attributes, bool checkReadOnly, PutPropertySlot& slot) { ASSERT(value); @@ -555,8 +614,7 @@ inline JSValue JSValue::get(ExecState* exec, const Identifier& propertyName, Pro while (true) { if (cell->fastGetOwnPropertySlot(exec, propertyName, slot)) return slot.getValue(exec, propertyName); - ASSERT(cell->isObject()); - JSValue prototype = static_cast<JSObject*>(cell)->prototype(); + JSValue prototype = asObject(cell)->prototype(); if (!prototype.isObject()) return jsUndefined(); cell = asObject(prototype); @@ -581,8 +639,7 @@ inline JSValue JSValue::get(ExecState* exec, unsigned propertyName, PropertySlot while (true) { if (cell->getOwnPropertySlot(exec, propertyName, slot)) return slot.getValue(exec, propertyName); - ASSERT(cell->isObject()); - JSValue prototype = static_cast<JSObject*>(cell)->prototype(); + JSValue prototype = asObject(cell)->prototype(); if (!prototype.isObject()) return jsUndefined(); cell = prototype.asCell(); @@ -627,6 +684,17 @@ ALWAYS_INLINE void JSObject::allocatePropertyStorageInline(size_t oldSize, size_ m_externalStorage = newPropertyStorage; } +ALWAYS_INLINE void JSObject::markChildrenDirect(MarkStack& markStack) +{ + JSCell::markChildren(markStack); + + markStack.append(prototype()); + + PropertyStorage storage = propertyStorage(); + size_t storageSize = m_structure->propertyStorageSize(); + markStack.appendValues(reinterpret_cast<JSValue*>(storage), storageSize); +} + } // namespace JSC #endif // JSObject_h diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.cpp b/JavaScriptCore/runtime/JSPropertyNameIterator.cpp index dc0304f..d3dcb83 100644 --- a/JavaScriptCore/runtime/JSPropertyNameIterator.cpp +++ b/JavaScriptCore/runtime/JSPropertyNameIterator.cpp @@ -29,62 +29,62 @@ #include "config.h" #include "JSPropertyNameIterator.h" +#include "JSGlobalObject.h" + namespace JSC { ASSERT_CLASS_FITS_IN_CELL(JSPropertyNameIterator); -JSPropertyNameIterator::~JSPropertyNameIterator() +JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSObject* o) { -} + ASSERT(!o->structure()->enumerationCache() || + o->structure()->enumerationCache()->cachedStructure() != o->structure() || + o->structure()->enumerationCache()->cachedPrototypeChain() != o->structure()->prototypeChain(exec)); -JSValue JSPropertyNameIterator::toPrimitive(ExecState*, PreferredPrimitiveType) const -{ - ASSERT_NOT_REACHED(); - return JSValue(); -} + PropertyNameArray propertyNames(exec); + o->getPropertyNames(exec, propertyNames); + size_t numCacheableSlots = 0; + if (!o->structure()->hasNonEnumerableProperties() && !o->structure()->hasAnonymousSlots() && + !o->structure()->hasGetterSetterProperties() && !o->structure()->isUncacheableDictionary() && + !o->structure()->typeInfo().overridesGetPropertyNames()) + numCacheableSlots = o->structure()->propertyStorageSize(); -bool JSPropertyNameIterator::getPrimitiveNumber(ExecState*, double&, JSValue&) -{ - ASSERT_NOT_REACHED(); - return false; -} + JSPropertyNameIterator* jsPropertyNameIterator = new (exec) JSPropertyNameIterator(exec, propertyNames.data(), numCacheableSlots); -bool JSPropertyNameIterator::toBoolean(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return false; -} + if (o->structure()->isDictionary()) + return jsPropertyNameIterator; -double JSPropertyNameIterator::toNumber(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return 0; -} + if (o->structure()->typeInfo().overridesGetPropertyNames()) + return jsPropertyNameIterator; + + size_t count = normalizePrototypeChain(exec, o); + StructureChain* structureChain = o->structure()->prototypeChain(exec); + RefPtr<Structure>* structure = structureChain->head(); + for (size_t i = 0; i < count; ++i) { + if (structure[i]->typeInfo().overridesGetPropertyNames()) + return jsPropertyNameIterator; + } -UString JSPropertyNameIterator::toString(ExecState*) const -{ - ASSERT_NOT_REACHED(); - return ""; + jsPropertyNameIterator->setCachedPrototypeChain(structureChain); + jsPropertyNameIterator->setCachedStructure(o->structure()); + o->structure()->setEnumerationCache(jsPropertyNameIterator); + return jsPropertyNameIterator; } -JSObject* JSPropertyNameIterator::toObject(ExecState*) const +JSValue JSPropertyNameIterator::get(ExecState* exec, JSObject* base, size_t i) { - ASSERT_NOT_REACHED(); - return 0; -} + JSValue& identifier = m_jsStrings[i]; + if (m_cachedStructure == base->structure() && m_cachedPrototypeChain == base->structure()->prototypeChain(exec)) + return identifier; -void JSPropertyNameIterator::markChildren(MarkStack& markStack) -{ - JSCell::markChildren(markStack); - if (m_object) - markStack.append(m_object); + if (!base->hasProperty(exec, Identifier(exec, asString(identifier)->value(exec)))) + return JSValue(); + return identifier; } -void JSPropertyNameIterator::invalidate() +void JSPropertyNameIterator::markChildren(MarkStack& markStack) { - ASSERT(m_position == m_end); - m_object = 0; - m_data.clear(); + markStack.appendValues(m_jsStrings.get(), m_jsStringsSize, MayContainNullValues); } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSPropertyNameIterator.h b/JavaScriptCore/runtime/JSPropertyNameIterator.h index 4534528..529ae8b 100644 --- a/JavaScriptCore/runtime/JSPropertyNameIterator.h +++ b/JavaScriptCore/runtime/JSPropertyNameIterator.h @@ -31,6 +31,7 @@ #include "JSObject.h" #include "JSString.h" +#include "Operations.h" #include "PropertyNameArray.h" namespace JSC { @@ -39,80 +40,63 @@ namespace JSC { class JSObject; class JSPropertyNameIterator : public JSCell { - public: - static JSPropertyNameIterator* create(ExecState*, JSValue); + friend class JIT; - virtual ~JSPropertyNameIterator(); + public: + static JSPropertyNameIterator* create(ExecState*, JSObject*); + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(CompoundType, OverridesMarkChildren)); + } - virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; - virtual bool getPrimitiveNumber(ExecState*, double&, JSValue&); - virtual bool toBoolean(ExecState*) const; - virtual double toNumber(ExecState*) const; - virtual UString toString(ExecState*) const; - virtual JSObject* toObject(ExecState*) const; + virtual bool isPropertyNameIterator() const { return true; } virtual void markChildren(MarkStack&); - JSValue next(ExecState*); - void invalidate(); - - static PassRefPtr<Structure> createStructure(JSValue prototype) + bool getOffset(size_t i, int& offset) { - return Structure::create(prototype, TypeInfo(CompoundType)); + if (i >= m_numCacheableSlots) + return false; + offset = i; + return true; } + + JSValue get(ExecState*, JSObject*, size_t i); + size_t size() { return m_jsStringsSize; } + + void setCachedStructure(Structure* structure) { m_cachedStructure = structure; } + Structure* cachedStructure() { return m_cachedStructure; } + + void setCachedPrototypeChain(NonNullPassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } + StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } + private: - JSPropertyNameIterator(ExecState*); - JSPropertyNameIterator(ExecState*, JSObject*, PassRefPtr<PropertyNameArrayData> propertyNameArrayData); + JSPropertyNameIterator(ExecState*, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlot); - JSObject* m_object; - RefPtr<PropertyNameArrayData> m_data; - PropertyNameArrayData::const_iterator m_position; - PropertyNameArrayData::const_iterator m_end; + Structure* m_cachedStructure; + RefPtr<StructureChain> m_cachedPrototypeChain; + uint32_t m_numCacheableSlots; + uint32_t m_jsStringsSize; + OwnArrayPtr<JSValue> m_jsStrings; }; -inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec) +inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, PropertyNameArrayData* propertyNameArrayData, size_t numCacheableSlots) : JSCell(exec->globalData().propertyNameIteratorStructure.get()) - , m_object(0) - , m_position(0) - , m_end(0) + , m_cachedStructure(0) + , m_numCacheableSlots(numCacheableSlots) + , m_jsStringsSize(propertyNameArrayData->propertyNameVector().size()) + , m_jsStrings(new JSValue[m_jsStringsSize]) { + PropertyNameArrayData::PropertyNameVector& propertyNameVector = propertyNameArrayData->propertyNameVector(); + for (size_t i = 0; i < m_jsStringsSize; ++i) + m_jsStrings[i] = jsOwnedString(exec, propertyNameVector[i].ustring()); } -inline JSPropertyNameIterator::JSPropertyNameIterator(ExecState* exec, JSObject* object, PassRefPtr<PropertyNameArrayData> propertyNameArrayData) - : JSCell(exec->globalData().propertyNameIteratorStructure.get()) - , m_object(object) - , m_data(propertyNameArrayData) - , m_position(m_data->begin()) - , m_end(m_data->end()) -{ -} - -inline JSPropertyNameIterator* JSPropertyNameIterator::create(ExecState* exec, JSValue v) +inline void Structure::setEnumerationCache(JSPropertyNameIterator* enumerationCache) { - if (v.isUndefinedOrNull()) - return new (exec) JSPropertyNameIterator(exec); - - JSObject* o = v.toObject(exec); - PropertyNameArray propertyNames(exec); - o->getPropertyNames(exec, propertyNames); - return new (exec) JSPropertyNameIterator(exec, o, propertyNames.releaseData()); -} - -inline JSValue JSPropertyNameIterator::next(ExecState* exec) -{ - if (m_position == m_end) - return JSValue(); - - if (m_data->cachedStructure() == m_object->structure() && m_data->cachedPrototypeChain() == m_object->structure()->prototypeChain(exec)) - return jsOwnedString(exec, (*m_position++).ustring()); - - do { - if (m_object->hasProperty(exec, *m_position)) - return jsOwnedString(exec, (*m_position++).ustring()); - m_position++; - } while (m_position != m_end); - - return JSValue(); + ASSERT(!isDictionary()); + m_enumerationCache = enumerationCache; } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSStaticScopeObject.h b/JavaScriptCore/runtime/JSStaticScopeObject.h index 5eb0e4b..2542878 100644 --- a/JavaScriptCore/runtime/JSStaticScopeObject.h +++ b/JavaScriptCore/runtime/JSStaticScopeObject.h @@ -57,7 +57,10 @@ namespace JSC{ virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes); - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, NeedsThisConversion)); } + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | NeedsThisConversion | OverridesMarkChildren | OverridesGetPropertyNames | JSVariableObject::StructureFlags; private: JSStaticScopeObjectData* d() { return static_cast<JSStaticScopeObjectData*>(JSVariableObject::d); } diff --git a/JavaScriptCore/runtime/JSString.cpp b/JavaScriptCore/runtime/JSString.cpp index 86f95e0..28ae6f7 100644 --- a/JavaScriptCore/runtime/JSString.cpp +++ b/JavaScriptCore/runtime/JSString.cpp @@ -25,41 +25,160 @@ #include "JSGlobalObject.h" #include "JSObject.h" +#include "Operations.h" #include "StringObject.h" #include "StringPrototype.h" namespace JSC { +void JSString::Rope::destructNonRecursive() +{ + Vector<Rope*, 32> workQueue; + Rope* rope = this; + + while (true) { + unsigned length = rope->ropeLength(); + for (unsigned i = 0; i < length; ++i) { + Fiber& fiber = rope->fibers(i); + if (fiber.isString()) + fiber.string()->deref(); + else { + Rope* nextRope = fiber.rope(); + if (nextRope->hasOneRef()) + workQueue.append(nextRope); + else + nextRope->deref(); + } + } + if (rope != this) + fastFree(rope); + + if (workQueue.isEmpty()) + return; + + rope = workQueue.last(); + workQueue.removeLast(); + } +} + +JSString::Rope::~Rope() +{ + destructNonRecursive(); +} + +#define ROPE_COPY_CHARS_INLINE_CUTOFF 20 + +static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) +{ +#ifdef ROPE_COPY_CHARS_INLINE_CUTOFF + if (numCharacters <= ROPE_COPY_CHARS_INLINE_CUTOFF) { + for (unsigned i = 0; i < numCharacters; ++i) + destination[i] = source[i]; + return; + } +#endif + memcpy(destination, source, numCharacters * sizeof(UChar)); +} + +// Overview: this methods converts a JSString from holding a string in rope form +// down to a simple UString representation. It does so by building up the string +// backwards, since we want to avoid recursion, we expect that the tree structure +// representing the rope is likely imbalanced with more nodes down the left side +// (since appending to the string is likely more common) - and as such resolving +// in this fashion should minimize work queue size. (If we built the queue forwards +// we would likely have to place all of the constituent UString::Reps into the +// Vector before performing any concatenation, but by working backwards we likely +// only fill the queue with the number of substrings at any given level in a +// rope-of-ropes.) +void JSString::resolveRope(ExecState* exec) const +{ + ASSERT(isRope()); + + // Allocate the buffer to hold the final string, position initially points to the end. + UChar* buffer; + if (!tryFastMalloc(m_stringLength * sizeof(UChar)).getValue(buffer)) { + for (unsigned i = 0; i < m_ropeLength; ++i) + m_fibers[i].deref(); + m_ropeLength = 0; + ASSERT(!isRope()); + ASSERT(m_value == UString()); + + throwOutOfMemoryError(exec); + return; + } + UChar* position = buffer + m_stringLength; + + // Start with the current Rope. + Vector<Rope::Fiber, 32> workQueue; + Rope::Fiber currentFiber; + for (unsigned i = 0; i < (m_ropeLength - 1); ++i) + workQueue.append(m_fibers[i]); + currentFiber = m_fibers[m_ropeLength - 1]; + while (true) { + if (currentFiber.isRope()) { + Rope* rope = currentFiber.rope(); + // Copy the contents of the current rope into the workQueue, with the last item in 'currentFiber' + // (we will be working backwards over the rope). + unsigned ropeLengthMinusOne = rope->ropeLength() - 1; + for (unsigned i = 0; i < ropeLengthMinusOne; ++i) + workQueue.append(rope->fibers(i)); + currentFiber = rope->fibers(ropeLengthMinusOne); + } else { + UString::Rep* string = currentFiber.string(); + unsigned length = string->len; + position -= length; + copyChars(position, string->data(), length); + + // Was this the last item in the work queue? + if (workQueue.isEmpty()) { + // Create a string from the UChar buffer, clear the rope RefPtr. + ASSERT(buffer == position); + m_value = UString::Rep::create(buffer, m_stringLength); + for (unsigned i = 0; i < m_ropeLength; ++i) + m_fibers[i].deref(); + m_ropeLength = 0; + + ASSERT(!isRope()); + return; + } + + // No! - set the next item up to process. + currentFiber = workQueue.last(); + workQueue.removeLast(); + } + } +} + JSValue JSString::toPrimitive(ExecState*, PreferredPrimitiveType) const { return const_cast<JSString*>(this); } -bool JSString::getPrimitiveNumber(ExecState*, double& number, JSValue& value) +bool JSString::getPrimitiveNumber(ExecState* exec, double& number, JSValue& result) { - value = this; - number = m_value.toDouble(); + result = this; + number = value(exec).toDouble(); return false; } bool JSString::toBoolean(ExecState*) const { - return !m_value.isEmpty(); + return m_stringLength; } -double JSString::toNumber(ExecState*) const +double JSString::toNumber(ExecState* exec) const { - return m_value.toDouble(); + return value(exec).toDouble(); } -UString JSString::toString(ExecState*) const +UString JSString::toString(ExecState* exec) const { - return m_value; + return value(exec); } -UString JSString::toThisString(ExecState*) const +UString JSString::toThisString(ExecState* exec) const { - return m_value; + return value(exec); } JSString* JSString::toThisJSString(ExecState*) @@ -103,54 +222,40 @@ bool JSString::getOwnPropertySlot(ExecState* exec, const Identifier& propertyNam return true; } -bool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +bool JSString::getStringPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { - // The semantics here are really getPropertySlot, not getOwnPropertySlot. - // This function should only be called by JSValue::get. - if (getStringPropertySlot(exec, propertyName, slot)) + if (propertyName == exec->propertyNames().length) { + descriptor.setDescriptor(jsNumber(exec, m_stringLength), DontEnum | DontDelete | ReadOnly); return true; - return JSString::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); -} - -JSString* jsString(JSGlobalData* globalData, const UString& s) -{ - int size = s.size(); - if (!size) - return globalData->smallStrings.emptyString(globalData); - if (size == 1) { - UChar c = s.data()[0]; - if (c <= 0xFF) - return globalData->smallStrings.singleCharacterString(globalData, c); } - return new (globalData) JSString(globalData, s); -} -JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length) -{ - ASSERT(offset <= static_cast<unsigned>(s.size())); - ASSERT(length <= static_cast<unsigned>(s.size())); - ASSERT(offset + length <= static_cast<unsigned>(s.size())); - if (!length) - return globalData->smallStrings.emptyString(globalData); - if (length == 1) { - UChar c = s.data()[offset]; - if (c <= 0xFF) - return globalData->smallStrings.singleCharacterString(globalData, c); + bool isStrictUInt32; + unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); + if (isStrictUInt32 && i < m_stringLength) { + descriptor.setDescriptor(jsSingleCharacterSubstring(exec, value(exec), i), DontDelete | ReadOnly); + return true; } - return new (globalData) JSString(globalData, UString::Rep::create(s.rep(), offset, length)); + + return false; } -JSString* jsOwnedString(JSGlobalData* globalData, const UString& s) +bool JSString::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) { - int size = s.size(); - if (!size) - return globalData->smallStrings.emptyString(globalData); - if (size == 1) { - UChar c = s.data()[0]; - if (c <= 0xFF) - return globalData->smallStrings.singleCharacterString(globalData, c); - } - return new (globalData) JSString(globalData, s, JSString::HasOtherOwner); + if (getStringPropertyDescriptor(exec, propertyName, descriptor)) + return true; + if (propertyName != exec->propertyNames().underscoreProto) + return false; + descriptor.setDescriptor(exec->lexicalGlobalObject()->stringPrototype(), DontEnum); + return true; +} + +bool JSString::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + // The semantics here are really getPropertySlot, not getOwnPropertySlot. + // This function should only be called by JSValue::get. + if (getStringPropertySlot(exec, propertyName, slot)) + return true; + return JSString::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSString.h b/JavaScriptCore/runtime/JSString.h index 3daf58a..93b11f1 100644 --- a/JavaScriptCore/runtime/JSString.h +++ b/JavaScriptCore/runtime/JSString.h @@ -27,6 +27,7 @@ #include "CommonIdentifiers.h" #include "Identifier.h" #include "JSNumberCell.h" +#include "PropertyDescriptor.h" #include "PropertySlot.h" namespace JSC { @@ -59,13 +60,110 @@ namespace JSC { JSString* jsOwnedString(ExecState*, const UString&); class JSString : public JSCell { + public: friend class JIT; friend struct VPtrSet; - public: + // A Rope is a string composed of a set of substrings. + class Rope : public RefCounted<Rope> { + public: + // A Rope is composed from a set of smaller strings called Fibers. + // Each Fiber in a rope is either UString::Rep or another Rope. + class Fiber { + public: + Fiber() {} + Fiber(UString::Rep* string) : m_value(reinterpret_cast<intptr_t>(string)) {} + Fiber(Rope* rope) : m_value(reinterpret_cast<intptr_t>(rope) | 1) {} + + void deref() + { + if (isRope()) + rope()->deref(); + else + string()->deref(); + } + + Fiber& ref() + { + if (isString()) + string()->ref(); + else + rope()->ref(); + return *this; + } + + unsigned refAndGetLength() + { + if (isString()) { + UString::Rep* rep = string(); + return rep->ref()->len; + } else { + Rope* r = rope(); + r->ref(); + return r->stringLength(); + } + } + + bool isRope() { return m_value & 1; } + Rope* rope() { return reinterpret_cast<Rope*>(m_value & ~1); } + bool isString() { return !isRope(); } + UString::Rep* string() { return reinterpret_cast<UString::Rep*>(m_value); } + + private: + intptr_t m_value; + }; + + // Creates a Rope comprising of 'ropeLength' Fibers. + // The Rope is constructed in an uninitialized state - initialize must be called for each Fiber in the Rope. + static PassRefPtr<Rope> createOrNull(unsigned ropeLength) + { + void* allocation; + if (tryFastMalloc(sizeof(Rope) + (ropeLength - 1) * sizeof(Fiber)).getValue(allocation)) + return adoptRef(new (allocation) Rope(ropeLength)); + return 0; + } + + ~Rope(); + void destructNonRecursive(); + + void append(unsigned &index, Fiber& fiber) + { + m_fibers[index++] = fiber; + m_stringLength += fiber.refAndGetLength(); + } + void append(unsigned &index, const UString& string) + { + UString::Rep* rep = string.rep(); + m_fibers[index++] = Fiber(rep); + m_stringLength += rep->ref()->len; + } + void append(unsigned& index, JSString* jsString) + { + if (jsString->isRope()) { + for (unsigned i = 0; i < jsString->m_ropeLength; ++i) + append(index, jsString->m_fibers[i]); + } else + append(index, jsString->string()); + } + + unsigned ropeLength() { return m_ropeLength; } + unsigned stringLength() { return m_stringLength; } + Fiber& fibers(unsigned index) { return m_fibers[index]; } + + private: + Rope(unsigned ropeLength) : m_ropeLength(ropeLength), m_stringLength(0) {} + void* operator new(size_t, void* inPlace) { return inPlace; } + + unsigned m_ropeLength; + unsigned m_stringLength; + Fiber m_fibers[1]; + }; + JSString(JSGlobalData* globalData, const UString& value) : JSCell(globalData->stringStructure.get()) + , m_stringLength(value.size()) , m_value(value) + , m_ropeLength(0) { Heap::heap(this)->reportExtraMemoryCost(value.cost()); } @@ -73,30 +171,115 @@ namespace JSC { enum HasOtherOwnerType { HasOtherOwner }; JSString(JSGlobalData* globalData, const UString& value, HasOtherOwnerType) : JSCell(globalData->stringStructure.get()) + , m_stringLength(value.size()) , m_value(value) + , m_ropeLength(0) { } JSString(JSGlobalData* globalData, PassRefPtr<UString::Rep> value, HasOtherOwnerType) : JSCell(globalData->stringStructure.get()) + , m_stringLength(value->size()) , m_value(value) + , m_ropeLength(0) { } - - const UString& value() const { return m_value; } + JSString(JSGlobalData* globalData, PassRefPtr<JSString::Rope> rope) + : JSCell(globalData->stringStructure.get()) + , m_stringLength(rope->stringLength()) + , m_ropeLength(1) + { + m_fibers[0] = rope.releaseRef(); + } + // This constructor constructs a new string by concatenating s1 & s2. + // This should only be called with ropeLength <= 3. + JSString(JSGlobalData* globalData, unsigned ropeLength, JSString* s1, JSString* s2) + : JSCell(globalData->stringStructure.get()) + , m_stringLength(s1->length() + s2->length()) + , m_ropeLength(ropeLength) + { + ASSERT(ropeLength <= s_maxInternalRopeLength); + unsigned index = 0; + appendStringInConstruct(index, s1); + appendStringInConstruct(index, s2); + ASSERT(ropeLength == index); + } + // This constructor constructs a new string by concatenating v1, v2 & v3. + // This should only be called with ropeLength <= 3 ... which since every + // value must require a ropeLength of at least one implies that the length + // for each value must be exactly 1! + JSString(ExecState* exec, JSValue v1, JSValue v2, JSValue v3) + : JSCell(exec->globalData().stringStructure.get()) + , m_stringLength(0) + , m_ropeLength(s_maxInternalRopeLength) + { + unsigned index = 0; + appendValueInConstructAndIncrementLength(exec, index, v1); + appendValueInConstructAndIncrementLength(exec, index, v2); + appendValueInConstructAndIncrementLength(exec, index, v3); + ASSERT(index == s_maxInternalRopeLength); + } + + ~JSString() + { + for (unsigned i = 0; i < m_ropeLength; ++i) + m_fibers[i].deref(); + } + + const UString& value(ExecState* exec) const + { + if (isRope()) + resolveRope(exec); + return m_value; + } + const UString tryGetValue() const + { + if (isRope()) + UString(); + return m_value; + } + unsigned length() { return m_stringLength; } bool getStringPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); bool getStringPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + bool getStringPropertyDescriptor(ExecState*, const Identifier& propertyName, PropertyDescriptor&); - bool canGetIndex(unsigned i) { return i < static_cast<unsigned>(m_value.size()); } - JSString* getIndex(JSGlobalData*, unsigned); + bool canGetIndex(unsigned i) { return i < m_stringLength; } + JSString* getIndex(ExecState*, unsigned); - static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, NeedsThisConversion)); } + static PassRefPtr<Structure> createStructure(JSValue proto) { return Structure::create(proto, TypeInfo(StringType, OverridesGetOwnPropertySlot | NeedsThisConversion)); } private: enum VPtrStealingHackType { VPtrStealingHack }; JSString(VPtrStealingHackType) : JSCell(0) + , m_ropeLength(0) + { + } + + void resolveRope(ExecState*) const; + + void appendStringInConstruct(unsigned& index, JSString* jsString) + { + if (jsString->isRope()) { + for (unsigned i = 0; i < jsString->m_ropeLength; ++i) + m_fibers[index++] = jsString->m_fibers[i].ref(); + } else + m_fibers[index++] = Rope::Fiber(jsString->string().rep()->ref()); + } + + void appendValueInConstructAndIncrementLength(ExecState* exec, unsigned& index, JSValue v) { + if (v.isString()) { + ASSERT(asCell(v)->isString()); + JSString* s = static_cast<JSString*>(asCell(v)); + ASSERT(s->ropeLength() == 1); + appendStringInConstruct(index, s); + m_stringLength += s->length(); + } else { + UString u(v.toString(exec)); + m_fibers[index++] = Rope::Fiber(u.rep()->ref()); + m_stringLength += u.size(); + } } virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const; @@ -113,8 +296,22 @@ namespace JSC { // Actually getPropertySlot, not getOwnPropertySlot (see JSCell). virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); + + static const unsigned s_maxInternalRopeLength = 3; + + // A string is represented either by a UString or a Rope. + unsigned m_stringLength; + mutable UString m_value; + mutable unsigned m_ropeLength; + mutable Rope::Fiber m_fibers[s_maxInternalRopeLength]; - UString m_value; + bool isRope() const { return m_ropeLength; } + UString& string() { ASSERT(!isRope()); return m_value; } + unsigned ropeLength() { return m_ropeLength ? m_ropeLength : 1; } + + friend JSValue jsString(ExecState* exec, JSString* s1, JSString* s2); + friend JSValue jsString(ExecState* exec, Register* strings, unsigned count); }; JSString* asString(JSValue); @@ -143,7 +340,7 @@ namespace JSC { UChar c = s.data()[offset]; if (c <= 0xFF) return globalData->smallStrings.singleCharacterString(globalData, c); - return new (globalData) JSString(globalData, UString::Rep::create(s.rep(), offset, 1)); + return new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, 1))); } inline JSString* jsNontrivialString(JSGlobalData* globalData, const char* s) @@ -160,10 +357,51 @@ namespace JSC { return new (globalData) JSString(globalData, s); } - inline JSString* JSString::getIndex(JSGlobalData* globalData, unsigned i) + inline JSString* JSString::getIndex(ExecState* exec, unsigned i) { ASSERT(canGetIndex(i)); - return jsSingleCharacterSubstring(globalData, m_value, i); + return jsSingleCharacterSubstring(&exec->globalData(), value(exec), i); + } + + inline JSString* jsString(JSGlobalData* globalData, const UString& s) + { + int size = s.size(); + if (!size) + return globalData->smallStrings.emptyString(globalData); + if (size == 1) { + UChar c = s.data()[0]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + } + return new (globalData) JSString(globalData, s); + } + + inline JSString* jsSubstring(JSGlobalData* globalData, const UString& s, unsigned offset, unsigned length) + { + ASSERT(offset <= static_cast<unsigned>(s.size())); + ASSERT(length <= static_cast<unsigned>(s.size())); + ASSERT(offset + length <= static_cast<unsigned>(s.size())); + if (!length) + return globalData->smallStrings.emptyString(globalData); + if (length == 1) { + UChar c = s.data()[offset]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + } + return new (globalData) JSString(globalData, UString(UString::Rep::create(s.rep(), offset, length))); + } + + inline JSString* jsOwnedString(JSGlobalData* globalData, const UString& s) + { + int size = s.size(); + if (!size) + return globalData->smallStrings.emptyString(globalData); + if (size == 1) { + UChar c = s.data()[0]; + if (c <= 0xFF) + return globalData->smallStrings.singleCharacterString(globalData, c); + } + return new (globalData) JSString(globalData, s, JSString::HasOtherOwner); } inline JSString* jsEmptyString(ExecState* exec) { return jsEmptyString(&exec->globalData()); } @@ -178,14 +416,14 @@ namespace JSC { ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot& slot) { if (propertyName == exec->propertyNames().length) { - slot.setValue(jsNumber(exec, m_value.size())); + slot.setValue(jsNumber(exec, m_stringLength)); return true; } bool isStrictUInt32; unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); - if (isStrictUInt32 && i < static_cast<unsigned>(m_value.size())) { - slot.setValue(jsSingleCharacterSubstring(exec, m_value, i)); + if (isStrictUInt32 && i < m_stringLength) { + slot.setValue(jsSingleCharacterSubstring(exec, value(exec), i)); return true; } @@ -194,8 +432,8 @@ namespace JSC { ALWAYS_INLINE bool JSString::getStringPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) { - if (propertyName < static_cast<unsigned>(m_value.size())) { - slot.setValue(jsSingleCharacterSubstring(exec, m_value, propertyName)); + if (propertyName < m_stringLength) { + slot.setValue(jsSingleCharacterSubstring(exec, value(exec), propertyName)); return true; } @@ -211,6 +449,26 @@ namespace JSC { return isCell() ? asCell()->toThisJSString(exec) : jsString(exec, toString(exec)); } + inline UString JSValue::toString(ExecState* exec) const + { + if (isString()) + return static_cast<JSString*>(asCell())->value(exec); + if (isInt32()) + return exec->globalData().numericStrings.add(asInt32()); + if (isDouble()) + return exec->globalData().numericStrings.add(asDouble()); + if (isTrue()) + return "true"; + if (isFalse()) + return "false"; + if (isNull()) + return "null"; + if (isUndefined()) + return "undefined"; + ASSERT(isCell()); + return asCell()->toString(exec); + } + } // namespace JSC #endif // JSString_h diff --git a/JavaScriptCore/runtime/JSType.h b/JavaScriptCore/runtime/JSType.h index a118b87..882b218 100644 --- a/JavaScriptCore/runtime/JSType.h +++ b/JavaScriptCore/runtime/JSType.h @@ -33,7 +33,6 @@ namespace JSC { NumberType = 3, NullType = 4, StringType = 5, - // The CompoundType value must come before any JSType that may have children CompoundType = 6, ObjectType = 7, diff --git a/JavaScriptCore/runtime/TypeInfo.h b/JavaScriptCore/runtime/JSTypeInfo.h index 70aeed3..7c89600 100644 --- a/JavaScriptCore/runtime/TypeInfo.h +++ b/JavaScriptCore/runtime/JSTypeInfo.h @@ -24,8 +24,11 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ -#ifndef TypeInfo_h -#define TypeInfo_h +#ifndef JSTypeInfo_h +#define JSTypeInfo_h + +// This file would be called TypeInfo.h, but that conflicts with <typeinfo.h> +// in the STL on systems without case-sensitive file systems. #include "JSType.h" @@ -37,7 +40,9 @@ namespace JSC { static const unsigned OverridesHasInstance = 1 << 2; static const unsigned ImplementsDefaultHasInstance = 1 << 3; static const unsigned NeedsThisConversion = 1 << 4; - static const unsigned HasStandardGetOwnPropertySlot = 1 << 5; + static const unsigned OverridesGetOwnPropertySlot = 1 << 5; + static const unsigned OverridesMarkChildren = 1 << 6; + static const unsigned OverridesGetPropertyNames = 1 << 7; class TypeInfo { friend class JIT; @@ -58,8 +63,9 @@ namespace JSC { 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; } - + bool overridesGetOwnPropertySlot() const { return m_flags & OverridesGetOwnPropertySlot; } + bool overridesMarkChildren() const { return m_flags & OverridesMarkChildren; } + bool overridesGetPropertyNames() const { return m_flags & OverridesGetPropertyNames; } unsigned flags() const { return m_flags; } private: @@ -69,4 +75,4 @@ namespace JSC { } -#endif // TypeInfo_h +#endif // JSTypeInfo_h diff --git a/JavaScriptCore/runtime/JSValue.cpp b/JavaScriptCore/runtime/JSValue.cpp index 39a4093..699c1cd 100644 --- a/JavaScriptCore/runtime/JSValue.cpp +++ b/JavaScriptCore/runtime/JSValue.cpp @@ -110,7 +110,10 @@ char* JSValue::description() { static const size_t size = 32; static char description[size]; - if (isInt32()) + + if (!*this) + snprintf(description, size, "<JSValue()>"); + else if (isInt32()) snprintf(description, size, "Int32: %d", asInt32()); else if (isDouble()) snprintf(description, size, "Double: %lf", asDouble()); diff --git a/JavaScriptCore/runtime/JSValue.h b/JavaScriptCore/runtime/JSValue.h index 408c187..fa5b5c0 100644 --- a/JavaScriptCore/runtime/JSValue.h +++ b/JavaScriptCore/runtime/JSValue.h @@ -20,15 +20,14 @@ * */ -#include <stddef.h> // for size_t -#include <stdint.h> - #ifndef JSValue_h #define JSValue_h #include "CallData.h" #include "ConstructData.h" #include <math.h> +#include <stddef.h> // for size_t +#include <stdint.h> #include <wtf/AlwaysInline.h> #include <wtf/Assertions.h> #include <wtf/HashTraits.h> @@ -42,7 +41,6 @@ namespace JSC { class JSImmediate; class JSObject; class JSString; - class MarkStack; class PropertySlot; class PutPropertySlot; class UString; @@ -82,6 +80,7 @@ namespace JSC { enum JSUndefinedTag { JSUndefined }; enum JSTrueTag { JSTrue }; enum JSFalseTag { JSFalse }; + enum EncodeAsDoubleTag { EncodeAsDouble }; JSValue(); JSValue(JSNullTag); @@ -92,6 +91,7 @@ namespace JSC { JSValue(const JSCell* ptr); // Numbers + JSValue(EncodeAsDoubleTag, ExecState*, double); JSValue(ExecState*, double); JSValue(ExecState*, char); JSValue(ExecState*, unsigned char); @@ -130,15 +130,15 @@ namespace JSC { bool isString() const; bool isGetterSetter() const; bool isObject() const; - bool isObject(const ClassInfo*) const; + bool inherits(const ClassInfo*) const; // Extracting the value. bool getBoolean(bool&) const; bool getBoolean() const; // false if not a boolean bool getNumber(double&) const; double uncheckedGetNumber() const; - bool getString(UString&) const; - UString getString() const; // null string if not a string + bool getString(ExecState* exec, UString&) const; + UString getString(ExecState* exec) const; // null string if not a string JSObject* getObject() const; // 0 if not an object CallType getCallData(CallData&); @@ -168,16 +168,14 @@ namespace JSC { uint32_t toUInt32(ExecState*) const; uint32_t toUInt32(ExecState*, bool& ok) const; +#if ENABLE(JSC_ZOMBIES) + bool isZombie() const; +#endif + // Floating point conversions (this is a convenience method for webcore; // signle precision float is not a representation used in JS or JSC). float toFloat(ExecState* exec) const { return static_cast<float>(toNumber(exec)); } - // Garbage collection. - void markChildren(MarkStack&); - bool hasChildren() const; - bool marked() const; - void markDirect(); - // Object operations, with the toObject operation included. JSValue get(ExecState*, const Identifier& propertyName) const; JSValue get(ExecState*, const Identifier& propertyName, PropertySlot&) const; @@ -194,9 +192,9 @@ namespace JSC { static bool equal(ExecState* exec, JSValue v1, JSValue v2); static bool equalSlowCase(ExecState* exec, JSValue v1, JSValue v2); static bool equalSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); - static bool strictEqual(JSValue v1, JSValue v2); - static bool strictEqualSlowCase(JSValue v1, JSValue v2); - static bool strictEqualSlowCaseInline(JSValue v1, JSValue v2); + static bool strictEqual(ExecState* exec, JSValue v1, JSValue v2); + static bool strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2); + static bool strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2); JSValue getJSNumber(); // JSValue() if this is not a JSNumber or number object @@ -221,7 +219,8 @@ namespace JSC { enum { FalseTag = 0xfffffffc }; enum { NullTag = 0xfffffffb }; enum { UndefinedTag = 0xfffffffa }; - enum { DeletedValueTag = 0xfffffff9 }; + enum { EmptyValueTag = 0xfffffff9 }; + enum { DeletedValueTag = 0xfffffff8 }; enum { LowestTag = DeletedValueTag }; @@ -286,6 +285,11 @@ namespace JSC { return b ? JSValue(JSValue::JSTrue) : JSValue(JSValue::JSFalse); } + ALWAYS_INLINE JSValue jsDoubleNumber(ExecState* exec, double d) + { + return JSValue(JSValue::EncodeAsDouble, exec, d); + } + ALWAYS_INLINE JSValue jsNumber(ExecState* exec, double d) { return JSValue(exec, d); @@ -380,6 +384,14 @@ namespace JSC { return static_cast<uint32_t>(val); } + // FIXME: We should deprecate this and just use JSValue::asCell() instead. + JSCell* asCell(JSValue); + + inline JSCell* asCell(JSValue value) + { + return value.asCell(); + } + ALWAYS_INLINE int32_t JSValue::toInt32(ExecState* exec) const { if (isInt32()) @@ -430,12 +442,15 @@ namespace JSC { { JSValue v; v.u.asEncodedJSValue = encodedJSValue; +#if ENABLE(JSC_ZOMBIES) + ASSERT(!v.isZombie()); +#endif return v; } inline JSValue::JSValue() { - u.asBits.tag = CellTag; + u.asBits.tag = EmptyValueTag; u.asBits.payload = 0; } @@ -471,19 +486,32 @@ namespace JSC { inline JSValue::JSValue(JSCell* ptr) { - u.asBits.tag = CellTag; + if (ptr) + u.asBits.tag = CellTag; + else + u.asBits.tag = EmptyValueTag; u.asBits.payload = reinterpret_cast<int32_t>(ptr); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif } inline JSValue::JSValue(const JSCell* ptr) { - u.asBits.tag = CellTag; + if (ptr) + u.asBits.tag = CellTag; + else + u.asBits.tag = EmptyValueTag; u.asBits.payload = reinterpret_cast<int32_t>(const_cast<JSCell*>(ptr)); +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif } inline JSValue::operator bool() const { - return u.asBits.payload || tag() != CellTag; + ASSERT(tag() != DeletedValueTag); + return tag() != EmptyValueTag; } inline bool JSValue::operator==(const JSValue& other) const @@ -575,6 +603,11 @@ namespace JSC { return reinterpret_cast<JSCell*>(u.asBits.payload); } + ALWAYS_INLINE JSValue::JSValue(EncodeAsDoubleTag, ExecState*, double d) + { + u.asDouble = d; + } + inline JSValue::JSValue(ExecState* exec, double d) { const int32_t asInt32 = static_cast<int32_t>(d); @@ -773,11 +806,17 @@ namespace JSC { inline JSValue::JSValue(JSCell* ptr) : m_ptr(ptr) { +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif } inline JSValue::JSValue(const JSCell* ptr) : m_ptr(const_cast<JSCell*>(ptr)) { +#if ENABLE(JSC_ZOMBIES) + ASSERT(!isZombie()); +#endif } inline JSValue::operator bool() const diff --git a/JavaScriptCore/runtime/JSVariableObject.cpp b/JavaScriptCore/runtime/JSVariableObject.cpp index a36cefa..3aa9e62 100644 --- a/JavaScriptCore/runtime/JSVariableObject.cpp +++ b/JavaScriptCore/runtime/JSVariableObject.cpp @@ -30,6 +30,7 @@ #include "JSVariableObject.h" #include "PropertyNameArray.h" +#include "PropertyDescriptor.h" namespace JSC { @@ -41,7 +42,7 @@ bool JSVariableObject::deleteProperty(ExecState* exec, const Identifier& propert return JSObject::deleteProperty(exec, propertyName); } -void JSVariableObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void JSVariableObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { SymbolTable::const_iterator end = symbolTable().end(); for (SymbolTable::const_iterator it = symbolTable().begin(); it != end; ++it) { @@ -49,22 +50,22 @@ void JSVariableObject::getPropertyNames(ExecState* exec, PropertyNameArray& prop propertyNames.add(Identifier(exec, it->first.get())); } - JSObject::getPropertyNames(exec, propertyNames); + JSObject::getOwnPropertyNames(exec, propertyNames); } -bool JSVariableObject::getPropertyAttributes(ExecState* exec, const Identifier& propertyName, unsigned& attributes) const +bool JSVariableObject::isVariableObject() const { - SymbolTableEntry entry = symbolTable().get(propertyName.ustring().rep()); - if (!entry.isNull()) { - attributes = entry.getAttributes() | DontDelete; - return true; - } - return JSObject::getPropertyAttributes(exec, propertyName, attributes); + return true; } -bool JSVariableObject::isVariableObject() const +bool JSVariableObject::symbolTableGet(const Identifier& propertyName, PropertyDescriptor& descriptor) { - return true; + SymbolTableEntry entry = symbolTable().inlineGet(propertyName.ustring().rep()); + if (!entry.isNull()) { + descriptor.setDescriptor(registerAt(entry.getIndex()).jsValue(), entry.getAttributes() | DontDelete); + return true; + } + return false; } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSVariableObject.h b/JavaScriptCore/runtime/JSVariableObject.h index b969da5..15d6ff5 100644 --- a/JavaScriptCore/runtime/JSVariableObject.h +++ b/JavaScriptCore/runtime/JSVariableObject.h @@ -49,16 +49,20 @@ namespace JSC { virtual void putWithAttributes(ExecState*, const Identifier&, JSValue, unsigned attributes) = 0; virtual bool deleteProperty(ExecState*, const Identifier&); - virtual void getPropertyNames(ExecState*, PropertyNameArray&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&); virtual bool isVariableObject() const; virtual bool isDynamicScope() const = 0; - virtual bool getPropertyAttributes(ExecState*, const Identifier& propertyName, unsigned& attributes) const; - Register& registerAt(int index) const { return d->registers[index]; } + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); + } + protected: + static const unsigned StructureFlags = OverridesGetPropertyNames | JSObject::StructureFlags; // 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). @@ -79,7 +83,7 @@ namespace JSC { JSVariableObjectData& operator=(const JSVariableObjectData&); }; - JSVariableObject(PassRefPtr<Structure> structure, JSVariableObjectData* data) + JSVariableObject(NonNullPassRefPtr<Structure> structure, JSVariableObjectData* data) : JSObject(structure) , d(data) // Subclass owns this pointer. { @@ -89,6 +93,7 @@ namespace JSC { void setRegisters(Register* r, Register* registerArray); bool symbolTableGet(const Identifier&, PropertySlot&); + bool symbolTableGet(const Identifier&, PropertyDescriptor&); bool symbolTableGet(const Identifier&, PropertySlot&, bool& slotIsWriteable); bool symbolTablePut(const Identifier&, JSValue); bool symbolTablePutWithAttributes(const Identifier&, JSValue, unsigned attributes); diff --git a/JavaScriptCore/runtime/JSWrapperObject.h b/JavaScriptCore/runtime/JSWrapperObject.h index 0b2c680..191ff3b 100644 --- a/JavaScriptCore/runtime/JSWrapperObject.h +++ b/JavaScriptCore/runtime/JSWrapperObject.h @@ -25,33 +25,41 @@ #include "JSObject.h" namespace JSC { - + // This class is used as a base for classes such as String, // Number, Boolean and Date which are wrappers for primitive types. class JSWrapperObject : public JSObject { protected: - explicit JSWrapperObject(PassRefPtr<Structure>); + explicit JSWrapperObject(NonNullPassRefPtr<Structure>); public: JSValue internalValue() const { return m_internalValue; } void setInternalValue(JSValue); - + + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); + } + + private: virtual void markChildren(MarkStack&); - private: JSValue m_internalValue; }; - - inline JSWrapperObject::JSWrapperObject(PassRefPtr<Structure> structure) + + inline JSWrapperObject::JSWrapperObject(NonNullPassRefPtr<Structure> structure) : JSObject(structure) { + addAnonymousSlots(1); + putAnonymousValue(0, jsNull()); } - + inline void JSWrapperObject::setInternalValue(JSValue value) { ASSERT(value); ASSERT(!value.isObject()); m_internalValue = value; + putAnonymousValue(0, value); } } // namespace JSC diff --git a/JavaScriptCore/runtime/JSZombie.cpp b/JavaScriptCore/runtime/JSZombie.cpp new file mode 100644 index 0000000..072d29b --- /dev/null +++ b/JavaScriptCore/runtime/JSZombie.cpp @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "JSZombie.h" +#include "ClassInfo.h" + +#if ENABLE(JSC_ZOMBIES) + +namespace JSC { + +const ClassInfo JSZombie::s_info = { "Zombie", 0, 0, 0 }; + +Structure* JSZombie::leakedZombieStructure() { + static Structure* structure = 0; + if (!structure) { + Structure::startIgnoringLeaks(); + structure = Structure::create(jsNull(), TypeInfo(UnspecifiedType)).releaseRef(); + Structure::stopIgnoringLeaks(); + } + return structure; +} + +} + +#endif // ENABLE(JSC_ZOMBIES) diff --git a/JavaScriptCore/runtime/JSZombie.h b/JavaScriptCore/runtime/JSZombie.h new file mode 100644 index 0000000..8b33ea6 --- /dev/null +++ b/JavaScriptCore/runtime/JSZombie.h @@ -0,0 +1,78 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef JSZombie_h +#define JSZombie_h + +#include "JSCell.h" + +#if ENABLE(JSC_ZOMBIES) +namespace JSC { + +class JSZombie : public JSCell { +public: + JSZombie(const ClassInfo* oldInfo, Structure* structure) + : JSCell(structure) + , m_oldInfo(oldInfo) + { + } + virtual bool isZombie() const { return true; } + virtual const ClassInfo* classInfo() const { return &s_info; } + static Structure* leakedZombieStructure(); + + virtual bool isGetterSetter() const { ASSERT_NOT_REACHED(); return false; } + virtual bool isAPIValueWrapper() const { ASSERT_NOT_REACHED(); return false; } + virtual bool isPropertyNameIterator() const { ASSERT_NOT_REACHED(); return false; } + virtual CallType getCallData(CallData&) { ASSERT_NOT_REACHED(); return CallTypeNone; } + virtual ConstructType getConstructData(ConstructData&) { ASSERT_NOT_REACHED(); return ConstructTypeNone; } + virtual bool getUInt32(uint32_t&) const { ASSERT_NOT_REACHED(); return false; } + virtual JSValue toPrimitive(ExecState*, PreferredPrimitiveType) const { ASSERT_NOT_REACHED(); return jsNull(); } + virtual bool getPrimitiveNumber(ExecState*, double&, JSValue&) { ASSERT_NOT_REACHED(); return false; } + virtual bool toBoolean(ExecState*) const { ASSERT_NOT_REACHED(); return false; } + virtual double toNumber(ExecState*) const { ASSERT_NOT_REACHED(); return 0.0; } + virtual UString toString(ExecState*) const { ASSERT_NOT_REACHED(); return ""; } + virtual JSObject* toObject(ExecState*) const { ASSERT_NOT_REACHED(); return 0; } + virtual void markChildren(MarkStack&) { ASSERT_NOT_REACHED(); } + virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&) { ASSERT_NOT_REACHED(); } + virtual void put(ExecState*, unsigned, JSValue) { ASSERT_NOT_REACHED(); } + virtual bool deleteProperty(ExecState*, const Identifier&) { ASSERT_NOT_REACHED(); return false; } + virtual bool deleteProperty(ExecState*, unsigned) { ASSERT_NOT_REACHED(); return false; } + virtual JSObject* toThisObject(ExecState*) const { ASSERT_NOT_REACHED(); return 0; } + virtual UString toThisString(ExecState*) const { ASSERT_NOT_REACHED(); return ""; } + virtual JSString* toThisJSString(ExecState*) { ASSERT_NOT_REACHED(); return 0; } + virtual JSValue getJSNumber() { ASSERT_NOT_REACHED(); return jsNull(); } + virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&) { ASSERT_NOT_REACHED(); return false; } + virtual bool getOwnPropertySlot(ExecState*, unsigned, PropertySlot&) { ASSERT_NOT_REACHED(); return false; } + + static const ClassInfo s_info; +private: + const ClassInfo* m_oldInfo; +}; + +} + +#endif // ENABLE(JSC_ZOMBIES) + +#endif // JSZombie_h diff --git a/JavaScriptCore/runtime/LiteralParser.cpp b/JavaScriptCore/runtime/LiteralParser.cpp index 17ec906..d242282 100644 --- a/JavaScriptCore/runtime/LiteralParser.cpp +++ b/JavaScriptCore/runtime/LiteralParser.cpp @@ -295,7 +295,10 @@ JSValue LiteralParser::parse(ParserState initialState) } doParseArrayStartExpression: case DoParseArrayStartExpression: { + TokenType lastToken = m_lexer.currentToken().type; if (m_lexer.next() == TokRBracket) { + if (lastToken == TokComma) + return JSValue(); m_lexer.next(); lastValue = objectStack.last(); objectStack.removeLast(); diff --git a/JavaScriptCore/runtime/LiteralParser.h b/JavaScriptCore/runtime/LiteralParser.h index bceee7c..0f8072b 100644 --- a/JavaScriptCore/runtime/LiteralParser.h +++ b/JavaScriptCore/runtime/LiteralParser.h @@ -89,7 +89,7 @@ namespace JSC { private: TokenType lex(LiteralParserToken&); - template <ParserMode parserMode> TokenType lexString(LiteralParserToken&); + template <ParserMode mode> TokenType lexString(LiteralParserToken&); TokenType lexNumber(LiteralParserToken&); LiteralParserToken m_currentToken; UString m_string; diff --git a/JavaScriptCore/runtime/Lookup.h b/JavaScriptCore/runtime/Lookup.h index 167f2bc..4d70689 100644 --- a/JavaScriptCore/runtime/Lookup.h +++ b/JavaScriptCore/runtime/Lookup.h @@ -51,7 +51,7 @@ namespace JSC { typedef PropertySlot::GetValueFunc GetFunction; typedef void (*PutFunction)(ExecState*, JSObject* baseObject, JSValue value); - class HashEntry { + class HashEntry : public FastAllocBase { public: void initialize(UString::Rep* key, unsigned char attributes, intptr_t v1, intptr_t v2) { @@ -186,6 +186,24 @@ namespace JSC { return true; } + template <class ThisImp, class ParentImp> + inline bool getStaticPropertyDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor) + { + const HashEntry* entry = table->entry(exec, propertyName); + + if (!entry) // not found, forward to parent + return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor); + + PropertySlot slot; + if (entry->attributes() & Function) + setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); + else + slot.setCustom(thisObj, entry->propertyGetter()); + + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } + /** * Simplified version of getStaticPropertySlot in case there are only functions. * Using this instead of getStaticPropertySlot allows 'this' to avoid implementing @@ -204,6 +222,27 @@ namespace JSC { setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); return true; } + + /** + * Simplified version of getStaticPropertyDescriptor in case there are only functions. + * Using this instead of getStaticPropertyDescriptor allows 'this' to avoid implementing + * a dummy getValueProperty. + */ + template <class ParentImp> + inline bool getStaticFunctionDescriptor(ExecState* exec, const HashTable* table, JSObject* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor) + { + if (static_cast<ParentImp*>(thisObj)->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor)) + return true; + + const HashEntry* entry = table->entry(exec, propertyName); + if (!entry) + return false; + + PropertySlot slot; + setUpStaticFunctionSlot(exec, entry, thisObj, propertyName, slot); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } /** * Simplified version of getStaticPropertySlot in case there are no functions, only "values". @@ -224,6 +263,25 @@ namespace JSC { } /** + * Simplified version of getStaticPropertyDescriptor in case there are no functions, only "values". + * Using this instead of getStaticPropertyDescriptor removes the need for a FuncImp class. + */ + template <class ThisImp, class ParentImp> + inline bool getStaticValueDescriptor(ExecState* exec, const HashTable* table, ThisImp* thisObj, const Identifier& propertyName, PropertyDescriptor& descriptor) + { + const HashEntry* entry = table->entry(exec, propertyName); + + if (!entry) // not found, forward to parent + return thisObj->ParentImp::getOwnPropertyDescriptor(exec, propertyName, descriptor); + + ASSERT(!(entry->attributes() & Function)); + PropertySlot slot; + slot.setCustom(thisObj, entry->propertyGetter()); + descriptor.setDescriptor(slot.getValue(exec, propertyName), entry->attributes()); + return true; + } + + /** * This one is for "put". * It looks up a hash entry for the property to be set. If an entry * is found it sets the value and returns true, else it returns false. diff --git a/JavaScriptCore/runtime/MarkStack.cpp b/JavaScriptCore/runtime/MarkStack.cpp index 80dbb17..a350c35 100644 --- a/JavaScriptCore/runtime/MarkStack.cpp +++ b/JavaScriptCore/runtime/MarkStack.cpp @@ -26,8 +26,7 @@ #include "config.h" #include "MarkStack.h" -namespace JSC -{ +namespace JSC { size_t MarkStack::s_pageSize = 0; diff --git a/JavaScriptCore/runtime/MarkStack.h b/JavaScriptCore/runtime/MarkStack.h index 7a7b3af..a114ae0 100644 --- a/JavaScriptCore/runtime/MarkStack.h +++ b/JavaScriptCore/runtime/MarkStack.h @@ -27,33 +27,27 @@ #define MarkStack_h #include "JSValue.h" - #include <wtf/Noncopyable.h> namespace JSC { + + class JSGlobalData; class Register; enum MarkSetProperties { MayContainNullValues, NoNullValues }; class MarkStack : Noncopyable { public: - MarkStack() - : m_markSets() - , m_values() - { - } - - ALWAYS_INLINE void append(JSValue value) + MarkStack(void* jsArrayVPtr) + : m_jsArrayVPtr(jsArrayVPtr) +#ifndef NDEBUG + , m_isCheckingForDefaultMarkViolation(false) +#endif { - ASSERT(value); - if (value.marked()) - return; - value.markDirect(); - if (value.hasChildren()) - m_values.append(value.asCell()); } - ALWAYS_INLINE void append(JSCell* cell); + ALWAYS_INLINE void append(JSValue); + void append(JSCell*); ALWAYS_INLINE void appendValues(Register* values, size_t count, MarkSetProperties properties = NoNullValues) { @@ -76,12 +70,15 @@ namespace JSC { } private: + void markChildren(JSCell*); + struct MarkSet { MarkSet(JSValue* values, JSValue* end, MarkSetProperties properties) : m_values(values) , m_end(end) , m_properties(properties) { + ASSERT(values); } JSValue* m_values; JSValue* m_end; @@ -136,6 +133,12 @@ namespace JSC { ASSERT(m_top); return m_data[--m_top]; } + + inline T& last() + { + ASSERT(m_top); + return m_data[m_top - 1]; + } inline bool isEmpty() { @@ -150,7 +153,14 @@ namespace JSC { ASSERT(0 == (size % MarkStack::pageSize())); if (size == m_allocated) return; +#if PLATFORM(WIN_OS) || PLATFORM(SYMBIAN) + // We cannot release a part of a region with VirtualFree. To get around this, + // we'll release the entire region and reallocate the size that we want. + releaseStack(m_data, m_allocated); + m_data = reinterpret_cast<T*>(allocateStack(size)); +#else releaseStack(reinterpret_cast<char*>(m_data) + size, m_allocated - size); +#endif m_allocated = size; m_capacity = m_allocated / sizeof(T); } @@ -162,9 +172,15 @@ namespace JSC { T* m_data; }; + void* m_jsArrayVPtr; MarkStackArray<MarkSet> m_markSets; MarkStackArray<JSCell*> m_values; static size_t s_pageSize; + +#ifndef NDEBUG + public: + bool m_isCheckingForDefaultMarkViolation; +#endif }; } diff --git a/JavaScriptCore/runtime/MarkStackSymbian.cpp b/JavaScriptCore/runtime/MarkStackSymbian.cpp new file mode 100644 index 0000000..a0ce8f6 --- /dev/null +++ b/JavaScriptCore/runtime/MarkStackSymbian.cpp @@ -0,0 +1,44 @@ +/* + Copyright (C) 2009 Nokia Corporation and/or its subsidiary(-ies) + + 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 "MarkStack.h" + +#include <e32hal.h> + +namespace JSC { + +void MarkStack::initializePagesize() +{ + TInt page_size; + UserHal::PageSizeInBytes(page_size); + MarkStack::s_pageSize = page_size; +} + +void* MarkStack::allocateStack(size_t size) +{ + return fastMalloc(size); +} + +void MarkStack::releaseStack(void* addr, size_t size) +{ + return fastFree(addr); +} + +} diff --git a/JavaScriptCore/runtime/MarkStackWin.cpp b/JavaScriptCore/runtime/MarkStackWin.cpp index dbc3306..1fdd06a 100644 --- a/JavaScriptCore/runtime/MarkStackWin.cpp +++ b/JavaScriptCore/runtime/MarkStackWin.cpp @@ -43,9 +43,11 @@ void* MarkStack::allocateStack(size_t size) { return VirtualAlloc(0, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE); } -void MarkStack::releaseStack(void* addr, size_t size) +void MarkStack::releaseStack(void* addr, size_t) { - VirtualFree(addr, size, MEM_RELEASE); + // According to http://msdn.microsoft.com/en-us/library/aa366892(VS.85).aspx, + // dwSize must be 0 if dwFreeType is MEM_RELEASE. + VirtualFree(addr, 0, MEM_RELEASE); } } diff --git a/JavaScriptCore/runtime/MathObject.cpp b/JavaScriptCore/runtime/MathObject.cpp index 2572bc9..98ff3ba 100644 --- a/JavaScriptCore/runtime/MathObject.cpp +++ b/JavaScriptCore/runtime/MathObject.cpp @@ -85,7 +85,7 @@ const ClassInfo MathObject::info = { "Math", 0, 0, ExecState::mathTable }; @end */ -MathObject::MathObject(ExecState* exec, PassRefPtr<Structure> structure) +MathObject::MathObject(ExecState* exec, NonNullPassRefPtr<Structure> structure) : JSObject(structure) { putDirectWithoutTransition(Identifier(exec, "E"), jsNumber(exec, exp(1.0)), DontDelete | DontEnum | ReadOnly); @@ -96,21 +96,18 @@ MathObject::MathObject(ExecState* exec, PassRefPtr<Structure> structure) putDirectWithoutTransition(Identifier(exec, "PI"), jsNumber(exec, piDouble), DontDelete | DontEnum | ReadOnly); putDirectWithoutTransition(Identifier(exec, "SQRT1_2"), jsNumber(exec, sqrt(0.5)), DontDelete | DontEnum | ReadOnly); putDirectWithoutTransition(Identifier(exec, "SQRT2"), jsNumber(exec, sqrt(2.0)), DontDelete | DontEnum | ReadOnly); - WTF::initializeWeakRandomNumberGenerator(); } // ECMA 15.8 bool MathObject::getOwnPropertySlot(ExecState* exec, const Identifier& propertyName, PropertySlot &slot) { - const HashEntry* entry = ExecState::mathTable(exec)->entry(exec, propertyName); - - if (!entry) - return JSObject::getOwnPropertySlot(exec, propertyName, slot); + return getStaticFunctionSlot<JSObject>(exec, ExecState::mathTable(exec), this, propertyName, slot); +} - ASSERT(entry->attributes() & Function); - setUpStaticFunctionSlot(exec, entry, this, propertyName, slot); - return true; +bool MathObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticFunctionDescriptor<JSObject>(exec, ExecState::mathTable(exec), this, propertyName, descriptor); } // ------------------------------ Functions -------------------------------- @@ -122,22 +119,22 @@ JSValue JSC_HOST_CALL mathProtoFuncAbs(ExecState* exec, JSObject*, JSValue, cons JSValue JSC_HOST_CALL mathProtoFuncACos(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, acos(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, acos(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncASin(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, asin(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, asin(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncATan(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, atan(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, atan(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncATan2(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, atan2(args.at(0).toNumber(exec), args.at(1).toNumber(exec))); + return jsDoubleNumber(exec, atan2(args.at(0).toNumber(exec), args.at(1).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -147,12 +144,12 @@ JSValue JSC_HOST_CALL mathProtoFuncCeil(ExecState* exec, JSObject*, JSValue, con JSValue JSC_HOST_CALL mathProtoFuncCos(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, cos(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, cos(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncExp(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, exp(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, exp(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -162,7 +159,7 @@ JSValue JSC_HOST_CALL mathProtoFuncFloor(ExecState* exec, JSObject*, JSValue, co JSValue JSC_HOST_CALL mathProtoFuncLog(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, log(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, log(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncMax(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -213,7 +210,7 @@ JSValue JSC_HOST_CALL mathProtoFuncPow(ExecState* exec, JSObject*, JSValue, cons JSValue JSC_HOST_CALL mathProtoFuncRandom(ExecState* exec, JSObject*, JSValue, const ArgList&) { - return jsNumber(exec, WTF::weakRandomNumber()); + return jsDoubleNumber(exec, exec->globalData().weakRandom.get()); } JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec, JSObject*, JSValue, const ArgList& args) @@ -226,17 +223,17 @@ JSValue JSC_HOST_CALL mathProtoFuncRound(ExecState* exec, JSObject*, JSValue, co JSValue JSC_HOST_CALL mathProtoFuncSin(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, sin(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, sin(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncSqrt(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, sqrt(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, sqrt(args.at(0).toNumber(exec))); } JSValue JSC_HOST_CALL mathProtoFuncTan(ExecState* exec, JSObject*, JSValue, const ArgList& args) { - return jsNumber(exec, tan(args.at(0).toNumber(exec))); + return jsDoubleNumber(exec, tan(args.at(0).toNumber(exec))); } } // namespace JSC diff --git a/JavaScriptCore/runtime/MathObject.h b/JavaScriptCore/runtime/MathObject.h index 3557d1e..7f474b8 100644 --- a/JavaScriptCore/runtime/MathObject.h +++ b/JavaScriptCore/runtime/MathObject.h @@ -27,17 +27,21 @@ namespace JSC { class MathObject : public JSObject { public: - MathObject(ExecState*, PassRefPtr<Structure>); + MathObject(ExecState*, NonNullPassRefPtr<Structure>); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; }; } // namespace JSC diff --git a/JavaScriptCore/runtime/NativeErrorConstructor.cpp b/JavaScriptCore/runtime/NativeErrorConstructor.cpp index 0205fc5..403fc7e 100644 --- a/JavaScriptCore/runtime/NativeErrorConstructor.cpp +++ b/JavaScriptCore/runtime/NativeErrorConstructor.cpp @@ -32,8 +32,8 @@ ASSERT_CLASS_FITS_IN_CELL(NativeErrorConstructor); const ClassInfo NativeErrorConstructor::info = { "Function", &InternalFunction::info, 0, 0 }; -NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, PassRefPtr<Structure> structure, NativeErrorPrototype* nativeErrorPrototype) - : InternalFunction(&exec->globalData(), structure, Identifier(exec, nativeErrorPrototype->getDirect(exec->propertyNames().name).getString())) +NativeErrorConstructor::NativeErrorConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, NativeErrorPrototype* nativeErrorPrototype) + : InternalFunction(&exec->globalData(), structure, Identifier(exec, nativeErrorPrototype->getDirect(exec->propertyNames().name).getString(exec))) , m_errorStructure(ErrorInstance::createStructure(nativeErrorPrototype)) { putDirect(exec->propertyNames().length, jsNumber(exec, 1), DontDelete | ReadOnly | DontEnum); // ECMA 15.11.7.5 diff --git a/JavaScriptCore/runtime/NativeErrorConstructor.h b/JavaScriptCore/runtime/NativeErrorConstructor.h index 118d1f4..152dbac 100644 --- a/JavaScriptCore/runtime/NativeErrorConstructor.h +++ b/JavaScriptCore/runtime/NativeErrorConstructor.h @@ -31,7 +31,7 @@ namespace JSC { class NativeErrorConstructor : public InternalFunction { public: - NativeErrorConstructor(ExecState*, PassRefPtr<Structure>, NativeErrorPrototype*); + NativeErrorConstructor(ExecState*, NonNullPassRefPtr<Structure>, NativeErrorPrototype*); static const ClassInfo info; diff --git a/JavaScriptCore/runtime/NativeErrorPrototype.cpp b/JavaScriptCore/runtime/NativeErrorPrototype.cpp index 84190a0..aa46a6a 100644 --- a/JavaScriptCore/runtime/NativeErrorPrototype.cpp +++ b/JavaScriptCore/runtime/NativeErrorPrototype.cpp @@ -29,7 +29,7 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(NativeErrorPrototype); -NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, PassRefPtr<Structure> structure, const UString& name, const UString& message) +NativeErrorPrototype::NativeErrorPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& name, const UString& message) : JSObject(structure) { putDirect(exec->propertyNames().name, jsString(exec, name), 0); diff --git a/JavaScriptCore/runtime/NativeErrorPrototype.h b/JavaScriptCore/runtime/NativeErrorPrototype.h index 77bfe8a..0c65a9c 100644 --- a/JavaScriptCore/runtime/NativeErrorPrototype.h +++ b/JavaScriptCore/runtime/NativeErrorPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class NativeErrorPrototype : public JSObject { public: - NativeErrorPrototype(ExecState*, PassRefPtr<Structure>, const UString& name, const UString& message); + NativeErrorPrototype(ExecState*, NonNullPassRefPtr<Structure>, const UString& name, const UString& message); }; } // namespace JSC diff --git a/JavaScriptCore/runtime/NumberConstructor.cpp b/JavaScriptCore/runtime/NumberConstructor.cpp index 2840bf0..cc6c51d 100644 --- a/JavaScriptCore/runtime/NumberConstructor.cpp +++ b/JavaScriptCore/runtime/NumberConstructor.cpp @@ -53,7 +53,7 @@ const ClassInfo NumberConstructor::info = { "Function", &InternalFunction::info, @end */ -NumberConstructor::NumberConstructor(ExecState* exec, PassRefPtr<Structure> structure, NumberPrototype* numberPrototype) +NumberConstructor::NumberConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, NumberPrototype* numberPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, numberPrototype->info.className)) { // Number.Prototype @@ -68,6 +68,11 @@ bool NumberConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& pr return getStaticValueSlot<NumberConstructor, InternalFunction>(exec, ExecState::numberTable(exec), this, propertyName, slot); } +bool NumberConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticValueDescriptor<NumberConstructor, InternalFunction>(exec, ExecState::numberTable(exec), this, propertyName, descriptor); +} + static JSValue numberConstructorNaNValue(ExecState* exec, const Identifier&, const PropertySlot&) { return jsNaN(exec); diff --git a/JavaScriptCore/runtime/NumberConstructor.h b/JavaScriptCore/runtime/NumberConstructor.h index b1224ec..cf19b6f 100644 --- a/JavaScriptCore/runtime/NumberConstructor.h +++ b/JavaScriptCore/runtime/NumberConstructor.h @@ -29,20 +29,24 @@ namespace JSC { class NumberConstructor : public InternalFunction { public: - NumberConstructor(ExecState*, PassRefPtr<Structure>, NumberPrototype*); + NumberConstructor(ExecState*, NonNullPassRefPtr<Structure>, NumberPrototype*); virtual bool getOwnPropertySlot(ExecState*, const Identifier&, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); JSValue getValueProperty(ExecState*, int token) const; static const ClassInfo info; static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, ImplementsHasInstance)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } enum { NaNValue, NegInfinity, PosInfinity, MaxValue, MinValue }; + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | InternalFunction::StructureFlags; + private: virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); diff --git a/JavaScriptCore/runtime/NumberObject.cpp b/JavaScriptCore/runtime/NumberObject.cpp index 0e8df17..1a7e44c 100644 --- a/JavaScriptCore/runtime/NumberObject.cpp +++ b/JavaScriptCore/runtime/NumberObject.cpp @@ -31,7 +31,7 @@ ASSERT_CLASS_FITS_IN_CELL(NumberObject); const ClassInfo NumberObject::info = { "Number", 0, 0, 0 }; -NumberObject::NumberObject(PassRefPtr<Structure> structure) +NumberObject::NumberObject(NonNullPassRefPtr<Structure> structure) : JSWrapperObject(structure) { } diff --git a/JavaScriptCore/runtime/NumberObject.h b/JavaScriptCore/runtime/NumberObject.h index d354b9b..8223a90 100644 --- a/JavaScriptCore/runtime/NumberObject.h +++ b/JavaScriptCore/runtime/NumberObject.h @@ -27,10 +27,22 @@ namespace JSC { class NumberObject : public JSWrapperObject { public: - explicit NumberObject(PassRefPtr<Structure>); + explicit NumberObject(NonNullPassRefPtr<Structure>); static const ClassInfo info; + static PassRefPtr<Structure> createStructure(JSValue prototype) + { + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); + } + + protected: +#if USE(JSVALUE32) + static const unsigned StructureFlags = OverridesMarkChildren | JSWrapperObject::StructureFlags; +#else + static const unsigned StructureFlags = JSWrapperObject::StructureFlags; +#endif + private: virtual const ClassInfo* classInfo() const { return &info; } diff --git a/JavaScriptCore/runtime/NumberPrototype.cpp b/JavaScriptCore/runtime/NumberPrototype.cpp index 947324c..df31404 100644 --- a/JavaScriptCore/runtime/NumberPrototype.cpp +++ b/JavaScriptCore/runtime/NumberPrototype.cpp @@ -45,7 +45,7 @@ static JSValue JSC_HOST_CALL numberProtoFuncToPrecision(ExecState*, JSObject*, J // ECMA 15.7.4 -NumberPrototype::NumberPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) +NumberPrototype::NumberPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) : NumberObject(structure) { setInternalValue(jsNumber(exec, 0)); diff --git a/JavaScriptCore/runtime/NumberPrototype.h b/JavaScriptCore/runtime/NumberPrototype.h index 0a3a544..1fb2077 100644 --- a/JavaScriptCore/runtime/NumberPrototype.h +++ b/JavaScriptCore/runtime/NumberPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class NumberPrototype : public NumberObject { public: - NumberPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + NumberPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); }; } // namespace JSC diff --git a/JavaScriptCore/runtime/NumericStrings.h b/JavaScriptCore/runtime/NumericStrings.h new file mode 100644 index 0000000..c0696a4 --- /dev/null +++ b/JavaScriptCore/runtime/NumericStrings.h @@ -0,0 +1,74 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef NumericStrings_h +#define NumericStrings_h + +#include "UString.h" +#include <wtf/HashFunctions.h> + +namespace JSC { + + class NumericStrings { + public: + UString add(double d) + { + CacheEntry<double>& entry = lookup(d); + if (d == entry.key && !entry.value.isNull()) + return entry.value; + entry.key = d; + entry.value = UString::from(d); + return entry.value; + } + + UString add(int i) + { + CacheEntry<int>& entry = lookup(i); + if (i == entry.key && !entry.value.isNull()) + return entry.value; + entry.key = i; + entry.value = UString::from(i); + return entry.value; + } + + private: + static const size_t cacheSize = 64; + + template<typename T> + struct CacheEntry { + T key; + UString value; + }; + + CacheEntry<double>& lookup(double d) { return doubleCache[WTF::FloatHash<double>::hash(d) & (cacheSize - 1)]; } + CacheEntry<int>& lookup(int i) { return intCache[WTF::IntHash<int>::hash(i) & (cacheSize - 1)]; } + + CacheEntry<double> doubleCache[cacheSize]; + CacheEntry<int> intCache[cacheSize]; + }; + +} // namespace JSC + +#endif // NumericStrings_h diff --git a/JavaScriptCore/runtime/ObjectConstructor.cpp b/JavaScriptCore/runtime/ObjectConstructor.cpp index 70c7cd1..693efc3 100644 --- a/JavaScriptCore/runtime/ObjectConstructor.cpp +++ b/JavaScriptCore/runtime/ObjectConstructor.cpp @@ -21,9 +21,13 @@ #include "config.h" #include "ObjectConstructor.h" +#include "Error.h" #include "JSFunction.h" +#include "JSArray.h" #include "JSGlobalObject.h" #include "ObjectPrototype.h" +#include "PropertyDescriptor.h" +#include "PropertyNameArray.h" #include "PrototypeFunction.h" namespace JSC { @@ -31,17 +35,27 @@ namespace JSC { ASSERT_CLASS_FITS_IN_CELL(ObjectConstructor); static JSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectConstructorKeys(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL objectConstructorCreate(ExecState*, JSObject*, JSValue, const ArgList&); -ObjectConstructor::ObjectConstructor(ExecState* exec, PassRefPtr<Structure> structure, ObjectPrototype* objectPrototype, Structure* prototypeFunctionStructure) - : InternalFunction(&exec->globalData(), structure, Identifier(exec, "Object")) +ObjectConstructor::ObjectConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, ObjectPrototype* objectPrototype, Structure* prototypeFunctionStructure) +: InternalFunction(&exec->globalData(), structure, Identifier(exec, "Object")) { // ECMA 15.2.3.1 putDirectWithoutTransition(exec->propertyNames().prototype, objectPrototype, DontEnum | DontDelete | ReadOnly); - + // no. of arguments for constructor putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 1), ReadOnly | DontEnum | DontDelete); - + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().getPrototypeOf, objectConstructorGetPrototypeOf), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().getOwnPropertyDescriptor, objectConstructorGetOwnPropertyDescriptor), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().keys, objectConstructorKeys), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 3, exec->propertyNames().defineProperty, objectConstructorDefineProperty), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().defineProperties, objectConstructorDefineProperties), DontEnum); + putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 2, exec->propertyNames().create, objectConstructorCreate), DontEnum); } // ECMA 15.2.2 @@ -82,4 +96,206 @@ JSValue JSC_HOST_CALL objectConstructorGetPrototypeOf(ExecState* exec, JSObject* return asObject(args.at(0))->prototype(); } +JSValue JSC_HOST_CALL objectConstructorGetOwnPropertyDescriptor(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (!args.at(0).isObject()) + return throwError(exec, TypeError, "Requested property descriptor of a value that is not an object."); + UString propertyName = args.at(1).toString(exec); + if (exec->hadException()) + return jsNull(); + JSObject* object = asObject(args.at(0)); + PropertyDescriptor descriptor; + if (!object->getOwnPropertyDescriptor(exec, Identifier(exec, propertyName), descriptor)) + return jsUndefined(); + if (exec->hadException()) + return jsUndefined(); + + JSObject* description = constructEmptyObject(exec); + if (!descriptor.isAccessorDescriptor()) { + description->putDirect(exec->propertyNames().value, descriptor.value() ? descriptor.value() : jsUndefined(), 0); + description->putDirect(exec->propertyNames().writable, jsBoolean(descriptor.writable()), 0); + } else { + description->putDirect(exec->propertyNames().get, descriptor.getter() ? descriptor.getter() : jsUndefined(), 0); + description->putDirect(exec->propertyNames().set, descriptor.setter() ? descriptor.setter() : jsUndefined(), 0); + } + + description->putDirect(exec->propertyNames().enumerable, jsBoolean(descriptor.enumerable()), 0); + description->putDirect(exec->propertyNames().configurable, jsBoolean(descriptor.configurable()), 0); + + return description; +} + +// FIXME: Use the enumeration cache. +JSValue JSC_HOST_CALL objectConstructorKeys(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (!args.at(0).isObject()) + return throwError(exec, TypeError, "Requested keys of a value that is not an object."); + PropertyNameArray properties(exec); + asObject(args.at(0))->getOwnPropertyNames(exec, properties); + JSArray* keys = constructEmptyArray(exec); + size_t numProperties = properties.size(); + for (size_t i = 0; i < numProperties; i++) + keys->push(exec, jsOwnedString(exec, properties[i].ustring())); + return keys; +} + +// ES5 8.10.5 ToPropertyDescriptor +static bool toPropertyDescriptor(ExecState* exec, JSValue in, PropertyDescriptor& desc) +{ + if (!in.isObject()) { + throwError(exec, TypeError, "Property description must be an object."); + return false; + } + JSObject* description = asObject(in); + + PropertySlot enumerableSlot(description); + if (description->getPropertySlot(exec, exec->propertyNames().enumerable, enumerableSlot)) { + desc.setEnumerable(enumerableSlot.getValue(exec, exec->propertyNames().enumerable).toBoolean(exec)); + if (exec->hadException()) + return false; + } + + PropertySlot configurableSlot(description); + if (description->getPropertySlot(exec, exec->propertyNames().configurable, configurableSlot)) { + desc.setConfigurable(configurableSlot.getValue(exec, exec->propertyNames().configurable).toBoolean(exec)); + if (exec->hadException()) + return false; + } + + JSValue value; + PropertySlot valueSlot(description); + if (description->getPropertySlot(exec, exec->propertyNames().value, valueSlot)) { + desc.setValue(valueSlot.getValue(exec, exec->propertyNames().value)); + if (exec->hadException()) + return false; + } + + PropertySlot writableSlot(description); + if (description->getPropertySlot(exec, exec->propertyNames().writable, writableSlot)) { + desc.setWritable(writableSlot.getValue(exec, exec->propertyNames().writable).toBoolean(exec)); + if (exec->hadException()) + return false; + } + + PropertySlot getSlot(description); + if (description->getPropertySlot(exec, exec->propertyNames().get, getSlot)) { + JSValue get = getSlot.getValue(exec, exec->propertyNames().get); + if (exec->hadException()) + return false; + if (!get.isUndefined()) { + CallData callData; + if (get.getCallData(callData) == CallTypeNone) { + throwError(exec, TypeError, "Getter must be a function."); + return false; + } + } else + get = JSValue(); + desc.setGetter(get); + } + + PropertySlot setSlot(description); + if (description->getPropertySlot(exec, exec->propertyNames().set, setSlot)) { + JSValue set = setSlot.getValue(exec, exec->propertyNames().set); + if (exec->hadException()) + return false; + if (!set.isUndefined()) { + CallData callData; + if (set.getCallData(callData) == CallTypeNone) { + throwError(exec, TypeError, "Setter must be a function."); + return false; + } + } else + set = JSValue(); + + desc.setSetter(set); + } + + if (!desc.isAccessorDescriptor()) + return true; + + if (desc.value()) { + throwError(exec, TypeError, "Invalid property. 'value' present on property with getter or setter."); + return false; + } + + if (desc.writablePresent()) { + throwError(exec, TypeError, "Invalid property. 'writable' present on property with getter or setter."); + return false; + } + return true; +} + +JSValue JSC_HOST_CALL objectConstructorDefineProperty(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (!args.at(0).isObject()) + return throwError(exec, TypeError, "Properties can only be defined on Objects."); + JSObject* O = asObject(args.at(0)); + UString propertyName = args.at(1).toString(exec); + if (exec->hadException()) + return jsNull(); + PropertyDescriptor descriptor; + if (!toPropertyDescriptor(exec, args.at(2), descriptor)) + return jsNull(); + ASSERT((descriptor.attributes() & (Getter | Setter)) || (!descriptor.isAccessorDescriptor())); + ASSERT(!exec->hadException()); + O->defineOwnProperty(exec, Identifier(exec, propertyName), descriptor, true); + return O; +} + +static JSValue defineProperties(ExecState* exec, JSObject* object, JSObject* properties) +{ + PropertyNameArray propertyNames(exec); + asObject(properties)->getOwnPropertyNames(exec, propertyNames); + size_t numProperties = propertyNames.size(); + Vector<PropertyDescriptor> descriptors; + MarkedArgumentBuffer markBuffer; + for (size_t i = 0; i < numProperties; i++) { + PropertySlot slot; + JSValue prop = properties->get(exec, propertyNames[i]); + if (exec->hadException()) + return jsNull(); + PropertyDescriptor descriptor; + if (!toPropertyDescriptor(exec, prop, descriptor)) + return jsNull(); + descriptors.append(descriptor); + // Ensure we mark all the values that we're accumulating + if (descriptor.isDataDescriptor() && descriptor.value()) + markBuffer.append(descriptor.value()); + if (descriptor.isAccessorDescriptor()) { + if (descriptor.getter()) + markBuffer.append(descriptor.getter()); + if (descriptor.setter()) + markBuffer.append(descriptor.setter()); + } + } + for (size_t i = 0; i < numProperties; i++) { + object->defineOwnProperty(exec, propertyNames[i], descriptors[i], true); + if (exec->hadException()) + return jsNull(); + } + return object; +} + +JSValue JSC_HOST_CALL objectConstructorDefineProperties(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (!args.at(0).isObject()) + return throwError(exec, TypeError, "Properties can only be defined on Objects."); + if (!args.at(1).isObject()) + return throwError(exec, TypeError, "Property descriptor list must be an Object."); + return defineProperties(exec, asObject(args.at(0)), asObject(args.at(1))); +} + +JSValue JSC_HOST_CALL objectConstructorCreate(ExecState* exec, JSObject*, JSValue, const ArgList& args) +{ + if (!args.at(0).isObject() && !args.at(0).isNull()) + return throwError(exec, TypeError, "Object prototype may only be an Object or null."); + JSObject* newObject = constructEmptyObject(exec); + newObject->setPrototype(args.at(0)); + if (args.at(1).isUndefined()) + return newObject; + if (!args.at(1).isObject()) + return throwError(exec, TypeError, "Property descriptor list must be an Object."); + return defineProperties(exec, newObject, asObject(args.at(1))); +} + } // namespace JSC diff --git a/JavaScriptCore/runtime/ObjectConstructor.h b/JavaScriptCore/runtime/ObjectConstructor.h index 9373781..1d2cdde 100644 --- a/JavaScriptCore/runtime/ObjectConstructor.h +++ b/JavaScriptCore/runtime/ObjectConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class ObjectConstructor : public InternalFunction { public: - ObjectConstructor(ExecState*, PassRefPtr<Structure>, ObjectPrototype*, Structure* prototypeFunctionStructure); + ObjectConstructor(ExecState*, NonNullPassRefPtr<Structure>, ObjectPrototype*, Structure* prototypeFunctionStructure); private: virtual ConstructType getConstructData(ConstructData&); diff --git a/JavaScriptCore/runtime/ObjectPrototype.cpp b/JavaScriptCore/runtime/ObjectPrototype.cpp index 98e4713..0970b7c 100644 --- a/JavaScriptCore/runtime/ObjectPrototype.cpp +++ b/JavaScriptCore/runtime/ObjectPrototype.cpp @@ -40,8 +40,9 @@ static JSValue JSC_HOST_CALL objectProtoFuncLookupSetter(ExecState*, JSObject*, static JSValue JSC_HOST_CALL objectProtoFuncPropertyIsEnumerable(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL objectProtoFuncToLocaleString(ExecState*, JSObject*, JSValue, const ArgList&); -ObjectPrototype::ObjectPrototype(ExecState* exec, PassRefPtr<Structure> stucture, Structure* prototypeFunctionStructure) +ObjectPrototype::ObjectPrototype(ExecState* exec, NonNullPassRefPtr<Structure> stucture, Structure* prototypeFunctionStructure) : JSObject(stucture) + , m_hasNoPropertiesWithUInt32Names(true) { putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toString, objectProtoFuncToString), DontEnum); putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().toLocaleString, objectProtoFuncToLocaleString), DontEnum); @@ -57,6 +58,24 @@ ObjectPrototype::ObjectPrototype(ExecState* exec, PassRefPtr<Structure> stucture putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 1, exec->propertyNames().__lookupSetter__, objectProtoFuncLookupSetter), DontEnum); } +void ObjectPrototype::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) +{ + JSObject::put(exec, propertyName, value, slot); + + if (m_hasNoPropertiesWithUInt32Names) { + bool isUInt32; + propertyName.toStrictUInt32(&isUInt32); + m_hasNoPropertiesWithUInt32Names = !isUInt32; + } +} + +bool ObjectPrototype::getOwnPropertySlot(ExecState* exec, unsigned propertyName, PropertySlot& slot) +{ + if (m_hasNoPropertiesWithUInt32Names) + return false; + return JSObject::getOwnPropertySlot(exec, propertyName, slot); +} + // ------------------------------ Functions -------------------------------- // ECMA 15.2.4.2, 15.2.4.4, 15.2.4.5, 15.2.4.7 diff --git a/JavaScriptCore/runtime/ObjectPrototype.h b/JavaScriptCore/runtime/ObjectPrototype.h index 7790ae0..489d962 100644 --- a/JavaScriptCore/runtime/ObjectPrototype.h +++ b/JavaScriptCore/runtime/ObjectPrototype.h @@ -27,7 +27,13 @@ namespace JSC { class ObjectPrototype : public JSObject { public: - ObjectPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + ObjectPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); + + private: + virtual void put(ExecState*, const Identifier&, JSValue, PutPropertySlot&); + virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + + bool m_hasNoPropertiesWithUInt32Names; }; JSValue JSC_HOST_CALL objectProtoFuncToString(ExecState*, JSObject*, JSValue, const ArgList&); diff --git a/JavaScriptCore/runtime/Operations.cpp b/JavaScriptCore/runtime/Operations.cpp index 093bbec..139c7b8 100644 --- a/JavaScriptCore/runtime/Operations.cpp +++ b/JavaScriptCore/runtime/Operations.cpp @@ -29,10 +29,6 @@ #include <stdio.h> #include <wtf/MathExtras.h> -#if HAVE(FLOAT_H) -#include <float.h> -#endif - namespace JSC { bool JSValue::equalSlowCase(ExecState* exec, JSValue v1, JSValue v2) @@ -40,9 +36,9 @@ bool JSValue::equalSlowCase(ExecState* exec, JSValue v1, JSValue v2) return equalSlowCaseInline(exec, v1, v2); } -bool JSValue::strictEqualSlowCase(JSValue v1, JSValue v2) +bool JSValue::strictEqualSlowCase(ExecState* exec, JSValue v1, JSValue v2) { - return strictEqualSlowCaseInline(v1, v2); + return strictEqualSlowCaseInline(exec, v1, v2); } NEVER_INLINE JSValue throwOutOfMemoryError(ExecState* exec) diff --git a/JavaScriptCore/runtime/Operations.h b/JavaScriptCore/runtime/Operations.h index c4900d3..1cab06d 100644 --- a/JavaScriptCore/runtime/Operations.h +++ b/JavaScriptCore/runtime/Operations.h @@ -35,6 +35,58 @@ namespace JSC { bool jsIsObjectType(JSValue); bool jsIsFunctionType(JSValue); + ALWAYS_INLINE JSValue jsString(ExecState* exec, JSString* s1, JSString* s2) + { + unsigned ropeLength = s1->ropeLength() + s2->ropeLength(); + JSGlobalData* globalData = &exec->globalData(); + + if (ropeLength <= JSString::s_maxInternalRopeLength) + return new (globalData) JSString(globalData, ropeLength, s1, s2); + + unsigned index = 0; + RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); + if (UNLIKELY(!rope)) + return throwOutOfMemoryError(exec); + rope->append(index, s1); + rope->append(index, s2); + ASSERT(index == ropeLength); + return new (globalData) JSString(globalData, rope.release()); + } + + ALWAYS_INLINE JSValue jsString(ExecState* exec, Register* strings, unsigned count) + { + ASSERT(count >= 3); + + unsigned ropeLength = 0; + for (unsigned i = 0; i < count; ++i) { + JSValue v = strings[i].jsValue(); + if (LIKELY(v.isString())) + ropeLength += asString(v)->ropeLength(); + else + ++ropeLength; + } + + JSGlobalData* globalData = &exec->globalData(); + if (ropeLength == 3) + return new (globalData) JSString(exec, strings[0].jsValue(), strings[1].jsValue(), strings[2].jsValue()); + + RefPtr<JSString::Rope> rope = JSString::Rope::createOrNull(ropeLength); + if (UNLIKELY(!rope)) + return throwOutOfMemoryError(exec); + + unsigned index = 0; + for (unsigned i = 0; i < count; ++i) { + JSValue v = strings[i].jsValue(); + if (LIKELY(v.isString())) + rope->append(index, asString(v)); + else + rope->append(index, v.toString(exec)); + } + + ASSERT(index == ropeLength); + return new (globalData) JSString(globalData, rope.release()); + } + // ECMA 11.9.3 inline bool JSValue::equal(ExecState* exec, JSValue v1, JSValue v2) { @@ -53,7 +105,7 @@ namespace JSC { bool s1 = v1.isString(); bool s2 = v2.isString(); if (s1 && s2) - return asString(v1)->value() == asString(v2)->value(); + return asString(v1)->value(exec) == asString(v2)->value(exec); if (v1.isUndefinedOrNull()) { if (v2.isUndefinedOrNull()) @@ -110,17 +162,17 @@ namespace JSC { } // ECMA 11.9.3 - ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(JSValue v1, JSValue v2) + ALWAYS_INLINE bool JSValue::strictEqualSlowCaseInline(ExecState* exec, JSValue v1, JSValue v2) { ASSERT(v1.isCell() && v2.isCell()); if (v1.asCell()->isString() && v2.asCell()->isString()) - return asString(v1)->value() == asString(v2)->value(); + return asString(v1)->value(exec) == asString(v2)->value(exec); return v1 == v2; } - inline bool JSValue::strictEqual(JSValue v1, JSValue v2) + inline bool JSValue::strictEqual(ExecState* exec, JSValue v1, JSValue v2) { if (v1.isInt32() && v2.isInt32()) return v1 == v2; @@ -131,7 +183,7 @@ namespace JSC { if (!v1.isCell() || !v2.isCell()) return v1 == v2; - return strictEqualSlowCaseInline(v1, v2); + return strictEqualSlowCaseInline(exec, v1, v2); } inline bool jsLess(CallFrame* callFrame, JSValue v1, JSValue v2) @@ -146,7 +198,7 @@ namespace JSC { JSGlobalData* globalData = &callFrame->globalData(); if (isJSString(globalData, v1) && isJSString(globalData, v2)) - return asString(v1)->value() < asString(v2)->value(); + return asString(v1)->value(callFrame) < asString(v2)->value(callFrame); JSValue p1; JSValue p2; @@ -156,7 +208,7 @@ namespace JSC { if (wasNotString1 | wasNotString2) return n1 < n2; - return asString(p1)->value() < asString(p2)->value(); + return asString(p1)->value(callFrame) < asString(p2)->value(callFrame); } inline bool jsLessEq(CallFrame* callFrame, JSValue v1, JSValue v2) @@ -171,7 +223,7 @@ namespace JSC { JSGlobalData* globalData = &callFrame->globalData(); if (isJSString(globalData, v1) && isJSString(globalData, v2)) - return !(asString(v2)->value() < asString(v1)->value()); + return !(asString(v2)->value(callFrame) < asString(v1)->value(callFrame)); JSValue p1; JSValue p2; @@ -181,7 +233,7 @@ namespace JSC { if (wasNotString1 | wasNotString2) return n1 <= n2; - return !(asString(p2)->value() < asString(p1)->value()); + return !(asString(p2)->value(callFrame) < asString(p1)->value(callFrame)); } // Fast-path choices here are based on frequency data from SunSpider: @@ -204,16 +256,17 @@ namespace JSC { bool leftIsString = v1.isString(); if (leftIsString && v2.isString()) { - RefPtr<UString::Rep> value = concatenate(asString(v1)->value().rep(), asString(v2)->value().rep()); - if (!value) - return throwOutOfMemoryError(callFrame); - return jsString(callFrame, value.release()); + if (!asString(v1)->length()) + return asString(v2); + if (!asString(v2)->length()) + return asString(v1); + return jsString(callFrame, asString(v1), asString(v2)); } if (rightIsNumber & leftIsString) { RefPtr<UString::Rep> value = v2.isInt32() ? - concatenate(asString(v1)->value().rep(), v2.asInt32()) : - concatenate(asString(v1)->value().rep(), right); + concatenate(asString(v1)->value(callFrame).rep(), v2.asInt32()) : + concatenate(asString(v1)->value(callFrame).rep(), right); if (!value) return throwOutOfMemoryError(callFrame); @@ -224,15 +277,15 @@ namespace JSC { return jsAddSlowCase(callFrame, v1, v2); } - inline size_t countPrototypeChainEntriesAndCheckForProxies(CallFrame* callFrame, JSValue baseValue, const PropertySlot& slot) + inline size_t normalizePrototypeChain(CallFrame* callFrame, JSValue base, JSValue slotBase) { - JSCell* cell = asCell(baseValue); + JSCell* cell = asCell(base); size_t count = 0; - while (slot.slotBase() != cell) { + while (slotBase != cell) { JSValue v = cell->structure()->prototypeForLookup(callFrame); - // If we didn't find slotBase in baseValue's prototype chain, then baseValue + // If we didn't find slotBase in base's prototype chain, then base // must be a proxy for another object. if (v.isNull()) @@ -243,7 +296,7 @@ namespace JSC { // Since we're accessing a prototype in a loop, it's a good bet that it // should not be treated as a dictionary. if (cell->structure()->isDictionary()) - asObject(cell)->setStructure(Structure::fromDictionaryTransition(cell->structure())); + asObject(cell)->flattenDictionaryObject(); ++count; } @@ -252,6 +305,25 @@ namespace JSC { return count; } + inline size_t normalizePrototypeChain(CallFrame* callFrame, JSCell* base) + { + size_t count = 0; + while (1) { + JSValue v = base->structure()->prototypeForLookup(callFrame); + if (v.isNull()) + return count; + + base = asCell(v); + + // Since we're accessing a prototype in a loop, it's a good bet that it + // should not be treated as a dictionary. + if (base->structure()->isDictionary()) + asObject(base)->flattenDictionaryObject(); + + ++count; + } + } + ALWAYS_INLINE JSValue resolveBase(CallFrame* callFrame, Identifier& property, ScopeChainNode* scopeChain) { ScopeChainIterator iter = scopeChain->begin(); @@ -274,59 +346,6 @@ namespace JSC { ASSERT_NOT_REACHED(); return JSValue(); } - - ALWAYS_INLINE JSValue concatenateStrings(CallFrame* callFrame, Register* strings, unsigned count) - { - ASSERT(count >= 3); - - // Estimate the amount of space required to hold the entire string. If all - // arguments are strings, we can easily calculate the exact amount of space - // required. For any other arguments, for now let's assume they may require - // 11 UChars of storage. This is enouch to hold any int, and likely is also - // reasonable for the other immediates. We may want to come back and tune - // this value at some point. - unsigned bufferSize = 0; - for (unsigned i = 0; i < count; ++i) { - JSValue v = strings[i].jsValue(); - if (LIKELY(v.isString())) - bufferSize += asString(v)->value().size(); - else - bufferSize += 11; - } - - // Allocate an output string to store the result. - // If the first argument is a String, and if it has the capacity (or can grow - // its capacity) to hold the entire result then use this as a base to concatenate - // onto. Otherwise, allocate a new empty output buffer. - JSValue firstValue = strings[0].jsValue(); - RefPtr<UString::Rep> resultRep; - if (firstValue.isString() && (resultRep = asString(firstValue)->value().rep())->reserveCapacity(bufferSize)) { - // We're going to concatenate onto the first string - remove it from the list of items to be appended. - ++strings; - --count; - } else - resultRep = UString::Rep::createEmptyBuffer(bufferSize); - UString result(resultRep); - - // Loop over the openards, writing them into the output buffer. - for (unsigned i = 0; i < count; ++i) { - JSValue v = strings[i].jsValue(); - if (LIKELY(v.isString())) - result.append(asString(v)->value()); - else if (v.isInt32()) - result.appendNumeric(v.asInt32()); - else { - double d; - if (v.getNumber(d)) - result.appendNumeric(d); - else - result.append(v.toString(callFrame)); - } - } - - return jsString(callFrame, result); - } - } // namespace JSC #endif // Operations_h diff --git a/JavaScriptCore/runtime/PropertyDescriptor.cpp b/JavaScriptCore/runtime/PropertyDescriptor.cpp new file mode 100644 index 0000000..558ae28 --- /dev/null +++ b/JavaScriptCore/runtime/PropertyDescriptor.cpp @@ -0,0 +1,195 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + + +#include "config.h" + +#include "PropertyDescriptor.h" + +#include "GetterSetter.h" +#include "JSObject.h" +#include "Operations.h" + +namespace JSC { +unsigned PropertyDescriptor::defaultAttributes = (DontDelete << 1) - 1; + +bool PropertyDescriptor::writable() const +{ + ASSERT(!isAccessorDescriptor()); + return !(m_attributes & ReadOnly); +} + +bool PropertyDescriptor::enumerable() const +{ + return !(m_attributes & DontEnum); +} + +bool PropertyDescriptor::configurable() const +{ + return !(m_attributes & DontDelete); +} + +bool PropertyDescriptor::isDataDescriptor() const +{ + return m_value || (m_seenAttributes & WritablePresent); +} + +bool PropertyDescriptor::isGenericDescriptor() const +{ + return !isAccessorDescriptor() && !isDataDescriptor(); +} + +bool PropertyDescriptor::isAccessorDescriptor() const +{ + return m_getter || m_setter; +} + +void PropertyDescriptor::setUndefined() +{ + m_value = jsUndefined(); + m_attributes = ReadOnly | DontDelete | DontEnum; +} + +JSValue PropertyDescriptor::getter() const +{ + ASSERT(isAccessorDescriptor()); + return m_getter; +} + +JSValue PropertyDescriptor::setter() const +{ + ASSERT(isAccessorDescriptor()); + return m_setter; +} + +void PropertyDescriptor::setDescriptor(JSValue value, unsigned attributes) +{ + ASSERT(value); + m_attributes = attributes; + if (attributes & (Getter | Setter)) { + GetterSetter* accessor = asGetterSetter(value); + m_getter = accessor->getter(); + m_setter = accessor->setter(); + ASSERT(m_getter || m_setter); + m_seenAttributes = EnumerablePresent | ConfigurablePresent; + m_attributes &= ~ReadOnly; + } else { + m_value = value; + m_seenAttributes = EnumerablePresent | ConfigurablePresent | WritablePresent; + } +} + +void PropertyDescriptor::setAccessorDescriptor(JSValue getter, JSValue setter, unsigned attributes) +{ + ASSERT(attributes & (Getter | Setter)); + ASSERT(getter || setter); + m_attributes = attributes; + m_getter = getter; + m_setter = setter; + m_attributes &= ~ReadOnly; + m_seenAttributes = EnumerablePresent | ConfigurablePresent; +} + +void PropertyDescriptor::setWritable(bool writable) +{ + if (writable) + m_attributes &= ~ReadOnly; + else + m_attributes |= ReadOnly; + m_seenAttributes |= WritablePresent; +} + +void PropertyDescriptor::setEnumerable(bool enumerable) +{ + if (enumerable) + m_attributes &= ~DontEnum; + else + m_attributes |= DontEnum; + m_seenAttributes |= EnumerablePresent; +} + +void PropertyDescriptor::setConfigurable(bool configurable) +{ + if (configurable) + m_attributes &= ~DontDelete; + else + m_attributes |= DontDelete; + m_seenAttributes |= ConfigurablePresent; +} + +void PropertyDescriptor::setSetter(JSValue setter) +{ + m_setter = setter; + m_attributes |= Setter; + m_attributes &= ~ReadOnly; +} + +void PropertyDescriptor::setGetter(JSValue getter) +{ + m_getter = getter; + m_attributes |= Getter; + m_attributes &= ~ReadOnly; +} + +bool PropertyDescriptor::equalTo(ExecState* exec, const PropertyDescriptor& other) const +{ + if (!other.m_value == m_value || + !other.m_getter == m_getter || + !other.m_setter == m_setter) + return false; + return (!m_value || JSValue::strictEqual(exec, other.m_value, m_value)) && + (!m_getter || JSValue::strictEqual(exec, other.m_getter, m_getter)) && + (!m_setter || JSValue::strictEqual(exec, other.m_setter, m_setter)) && + attributesEqual(other); +} + +bool PropertyDescriptor::attributesEqual(const PropertyDescriptor& other) const +{ + unsigned mismatch = other.m_attributes ^ m_attributes; + unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes; + if (sharedSeen & WritablePresent && mismatch & ReadOnly) + return false; + if (sharedSeen & ConfigurablePresent && mismatch & DontDelete) + return false; + if (sharedSeen & EnumerablePresent && mismatch & DontEnum) + return false; + return true; +} + +unsigned PropertyDescriptor::attributesWithOverride(const PropertyDescriptor& other) const +{ + unsigned mismatch = other.m_attributes ^ m_attributes; + unsigned sharedSeen = other.m_seenAttributes & m_seenAttributes; + unsigned newAttributes = m_attributes & defaultAttributes; + if (sharedSeen & WritablePresent && mismatch & ReadOnly) + newAttributes ^= ReadOnly; + if (sharedSeen & ConfigurablePresent && mismatch & DontDelete) + newAttributes ^= DontDelete; + if (sharedSeen & EnumerablePresent && mismatch & DontEnum) + newAttributes ^= DontEnum; + return newAttributes; +} + +} diff --git a/JavaScriptCore/runtime/PropertyDescriptor.h b/JavaScriptCore/runtime/PropertyDescriptor.h new file mode 100644 index 0000000..ff9f160 --- /dev/null +++ b/JavaScriptCore/runtime/PropertyDescriptor.h @@ -0,0 +1,80 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PropertyDescriptor_h +#define PropertyDescriptor_h + +#include "JSValue.h" + +namespace JSC { + class PropertyDescriptor { + public: + PropertyDescriptor() + : m_attributes(defaultAttributes) + , m_seenAttributes(0) + { + } + bool writable() const; + bool enumerable() const; + bool configurable() const; + bool isDataDescriptor() const; + bool isGenericDescriptor() const; + bool isAccessorDescriptor() const; + unsigned attributes() const { return m_attributes; } + JSValue value() const { return m_value; } + JSValue getter() const; + JSValue setter() const; + void setUndefined(); + void setDescriptor(JSValue value, unsigned attributes); + void setAccessorDescriptor(JSValue getter, JSValue setter, unsigned attributes); + void setWritable(bool); + void setEnumerable(bool); + void setConfigurable(bool); + void setValue(JSValue value) { m_value = value; } + void setSetter(JSValue); + void setGetter(JSValue); + bool isEmpty() const { return !(m_value || m_getter || m_setter || m_seenAttributes); } + bool writablePresent() const { return m_seenAttributes & WritablePresent; } + bool enumerablePresent() const { return m_seenAttributes & EnumerablePresent; } + bool configurablePresent() const { return m_seenAttributes & ConfigurablePresent; } + bool setterPresent() const { return m_setter; } + bool getterPresent() const { return m_getter; } + bool equalTo(ExecState* exec, const PropertyDescriptor& other) const; + bool attributesEqual(const PropertyDescriptor& other) const; + unsigned attributesWithOverride(const PropertyDescriptor& other) const; + private: + static unsigned defaultAttributes; + bool operator==(const PropertyDescriptor&){ return false; } + enum { WritablePresent = 1, EnumerablePresent = 2, ConfigurablePresent = 4}; + // May be a getter/setter + JSValue m_value; + JSValue m_getter; + JSValue m_setter; + unsigned m_attributes; + unsigned m_seenAttributes; + }; +} + +#endif diff --git a/JavaScriptCore/runtime/PropertyMapHashTable.h b/JavaScriptCore/runtime/PropertyMapHashTable.h index 44dc2b8..5b63f79 100644 --- a/JavaScriptCore/runtime/PropertyMapHashTable.h +++ b/JavaScriptCore/runtime/PropertyMapHashTable.h @@ -61,6 +61,7 @@ namespace JSC { unsigned size; unsigned keyCount; unsigned deletedSentinelCount; + unsigned anonymousSlotCount; unsigned lastIndexUsed; Vector<unsigned>* deletedOffsets; unsigned entryIndices[1]; diff --git a/JavaScriptCore/runtime/PropertyNameArray.cpp b/JavaScriptCore/runtime/PropertyNameArray.cpp index 0878e73..c28b6a4 100644 --- a/JavaScriptCore/runtime/PropertyNameArray.cpp +++ b/JavaScriptCore/runtime/PropertyNameArray.cpp @@ -21,6 +21,9 @@ #include "config.h" #include "PropertyNameArray.h" +#include "Structure.h" +#include "StructureChain.h" + namespace JSC { static const size_t setThreshold = 20; @@ -44,7 +47,7 @@ void PropertyNameArray::add(UString::Rep* identifier) return; } - m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); + addKnownUnique(identifier); } } // namespace JSC diff --git a/JavaScriptCore/runtime/PropertyNameArray.h b/JavaScriptCore/runtime/PropertyNameArray.h index b4382f4..3dbcc9d 100644 --- a/JavaScriptCore/runtime/PropertyNameArray.h +++ b/JavaScriptCore/runtime/PropertyNameArray.h @@ -23,45 +23,35 @@ #include "CallFrame.h" #include "Identifier.h" -#include "Structure.h" #include <wtf/HashSet.h> +#include <wtf/OwnArrayPtr.h> #include <wtf/Vector.h> namespace JSC { + + class Structure; + class StructureChain; + // FIXME: Rename to PropertyNameArray. class PropertyNameArrayData : public RefCounted<PropertyNameArrayData> { public: typedef Vector<Identifier, 20> PropertyNameVector; - typedef PropertyNameVector::const_iterator const_iterator; static PassRefPtr<PropertyNameArrayData> create() { return adoptRef(new PropertyNameArrayData); } - const_iterator begin() const { return m_propertyNameVector.begin(); } - const_iterator end() const { return m_propertyNameVector.end(); } - PropertyNameVector& propertyNameVector() { return m_propertyNameVector; } - void setCachedStructure(Structure* structure) { m_cachedStructure = structure; } - Structure* cachedStructure() const { return m_cachedStructure; } - - void setCachedPrototypeChain(PassRefPtr<StructureChain> cachedPrototypeChain) { m_cachedPrototypeChain = cachedPrototypeChain; } - StructureChain* cachedPrototypeChain() { return m_cachedPrototypeChain.get(); } - private: PropertyNameArrayData() - : m_cachedStructure(0) { } PropertyNameVector m_propertyNameVector; - Structure* m_cachedStructure; - RefPtr<StructureChain> m_cachedPrototypeChain; }; + // FIXME: Rename to PropertyNameArrayBuilder. class PropertyNameArray { public: - typedef PropertyNameArrayData::const_iterator const_iterator; - PropertyNameArray(JSGlobalData* globalData) : m_data(PropertyNameArrayData::create()) , m_globalData(globalData) @@ -82,21 +72,18 @@ namespace JSC { void add(UString::Rep*); void addKnownUnique(UString::Rep* identifier) { m_data->propertyNameVector().append(Identifier(m_globalData, identifier)); } - size_t size() const { return m_data->propertyNameVector().size(); } - Identifier& operator[](unsigned i) { return m_data->propertyNameVector()[i]; } const Identifier& operator[](unsigned i) const { return m_data->propertyNameVector()[i]; } - const_iterator begin() const { return m_data->begin(); } - const_iterator end() const { return m_data->end(); } - void setData(PassRefPtr<PropertyNameArrayData> data) { m_data = data; } PropertyNameArrayData* data() { return m_data.get(); } - PassRefPtr<PropertyNameArrayData> releaseData() { return m_data.release(); } - void setShouldCache(bool shouldCache) { m_shouldCache = shouldCache; } - bool shouldCache() const { return m_shouldCache; } + // FIXME: Remove these functions. + typedef PropertyNameArrayData::PropertyNameVector::const_iterator const_iterator; + size_t size() const { return m_data->propertyNameVector().size(); } + const_iterator begin() const { return m_data->propertyNameVector().begin(); } + const_iterator end() const { return m_data->propertyNameVector().end(); } private: typedef HashSet<UString::Rep*, PtrHash<UString::Rep*> > IdentifierSet; diff --git a/JavaScriptCore/runtime/PropertySlot.cpp b/JavaScriptCore/runtime/PropertySlot.cpp index 36fa5d8..a0a2f48 100644 --- a/JavaScriptCore/runtime/PropertySlot.cpp +++ b/JavaScriptCore/runtime/PropertySlot.cpp @@ -23,7 +23,6 @@ #include "JSFunction.h" #include "JSGlobalObject.h" -#include "JSObject.h" namespace JSC { @@ -39,7 +38,7 @@ JSValue PropertySlot::functionGetter(ExecState* exec, const Identifier&, const P return callData.native.function(exec, slot.m_data.getterFunc, slot.slotBase(), exec->emptyList()); ASSERT(callType == CallTypeJS); // FIXME: Can this be done more efficiently using the callData? - return static_cast<JSFunction*>(slot.m_data.getterFunc)->call(exec, slot.slotBase(), exec->emptyList()); + return asFunction(slot.m_data.getterFunc)->call(exec, slot.slotBase(), exec->emptyList()); } } // namespace JSC diff --git a/JavaScriptCore/runtime/Protect.h b/JavaScriptCore/runtime/Protect.h index 224164d..a0d5443 100644 --- a/JavaScriptCore/runtime/Protect.h +++ b/JavaScriptCore/runtime/Protect.h @@ -22,8 +22,8 @@ #ifndef Protect_h #define Protect_h -#include "JSCell.h" #include "Collector.h" +#include "JSValue.h" namespace JSC { diff --git a/JavaScriptCore/runtime/PrototypeFunction.cpp b/JavaScriptCore/runtime/PrototypeFunction.cpp index 8e3d107..38f8adb 100644 --- a/JavaScriptCore/runtime/PrototypeFunction.cpp +++ b/JavaScriptCore/runtime/PrototypeFunction.cpp @@ -40,7 +40,7 @@ PrototypeFunction::PrototypeFunction(ExecState* exec, int length, const Identifi putDirect(exec->propertyNames().length, jsNumber(exec, length), DontDelete | ReadOnly | DontEnum); } -PrototypeFunction::PrototypeFunction(ExecState* exec, PassRefPtr<Structure> prototypeFunctionStructure, int length, const Identifier& name, NativeFunction function) +PrototypeFunction::PrototypeFunction(ExecState* exec, NonNullPassRefPtr<Structure> prototypeFunctionStructure, int length, const Identifier& name, NativeFunction function) : InternalFunction(&exec->globalData(), prototypeFunctionStructure, name) , m_function(function) { diff --git a/JavaScriptCore/runtime/PrototypeFunction.h b/JavaScriptCore/runtime/PrototypeFunction.h index 99ab327..70ee034 100644 --- a/JavaScriptCore/runtime/PrototypeFunction.h +++ b/JavaScriptCore/runtime/PrototypeFunction.h @@ -32,7 +32,7 @@ namespace JSC { class PrototypeFunction : public InternalFunction { public: PrototypeFunction(ExecState*, int length, const Identifier&, NativeFunction); - PrototypeFunction(ExecState*, PassRefPtr<Structure>, int length, const Identifier&, NativeFunction); + PrototypeFunction(ExecState*, NonNullPassRefPtr<Structure>, int length, const Identifier&, NativeFunction); private: virtual CallType getCallData(CallData&); diff --git a/JavaScriptCore/runtime/RegExpConstructor.cpp b/JavaScriptCore/runtime/RegExpConstructor.cpp index 6a8089d..e5c6909 100644 --- a/JavaScriptCore/runtime/RegExpConstructor.cpp +++ b/JavaScriptCore/runtime/RegExpConstructor.cpp @@ -23,6 +23,7 @@ #include "RegExpConstructor.h" #include "ArrayPrototype.h" +#include "Error.h" #include "JSArray.h" #include "JSFunction.h" #include "JSString.h" @@ -89,29 +90,7 @@ const ClassInfo RegExpConstructor::info = { "Function", &InternalFunction::info, @end */ -struct RegExpConstructorPrivate : FastAllocBase { - // Global search cache / settings - RegExpConstructorPrivate() - : lastNumSubPatterns(0) - , multiline(false) - , lastOvectorIndex(0) - { - } - - const Vector<int, 32>& lastOvector() const { return ovector[lastOvectorIndex]; } - Vector<int, 32>& lastOvector() { return ovector[lastOvectorIndex]; } - Vector<int, 32>& tempOvector() { return ovector[lastOvectorIndex ? 0 : 1]; } - void changeLastOvector() { lastOvectorIndex = lastOvectorIndex ? 0 : 1; } - - UString input; - UString lastInput; - Vector<int, 32> ovector[2]; - unsigned lastNumSubPatterns : 30; - bool multiline : 1; - unsigned lastOvectorIndex : 1; -}; - -RegExpConstructor::RegExpConstructor(ExecState* exec, PassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype) +RegExpConstructor::RegExpConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, RegExpPrototype* regExpPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, "RegExp")) , d(new RegExpConstructorPrivate) { @@ -122,30 +101,6 @@ RegExpConstructor::RegExpConstructor(ExecState* exec, PassRefPtr<Structure> stru putDirectWithoutTransition(exec->propertyNames().length, jsNumber(exec, 2), ReadOnly | DontDelete | DontEnum); } -/* - To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular - expression matching through the performMatch function. We use cached results to calculate, - e.g., RegExp.lastMatch and RegExp.leftParen. -*/ -void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector) -{ - position = r->match(s, startOffset, &d->tempOvector()); - - if (ovector) - *ovector = d->tempOvector().data(); - - if (position != -1) { - ASSERT(!d->tempOvector().isEmpty()); - - length = d->tempOvector()[1] - d->tempOvector()[0]; - - d->input = s; - d->lastInput = s; - d->changeLastOvector(); - d->lastNumSubPatterns = r->numSubpatterns(); - } -} - RegExpMatchesArray::RegExpMatchesArray(ExecState* exec, RegExpConstructorPrivate* data) : JSArray(exec->lexicalGlobalObject()->regExpMatchesArrayStructure(), data->lastNumSubPatterns + 1) { @@ -177,6 +132,8 @@ void RegExpMatchesArray::fillArrayInstance(ExecState* exec) int start = d->lastOvector()[2 * i]; if (start >= 0) JSArray::put(exec, i, jsSubstring(exec, d->lastInput, start, d->lastOvector()[2 * i + 1] - start)); + else + JSArray::put(exec, i, jsUndefined()); } PutPropertySlot slot; @@ -233,6 +190,11 @@ bool RegExpConstructor::getOwnPropertySlot(ExecState* exec, const Identifier& pr return getStaticValueSlot<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, slot); } +bool RegExpConstructor::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticValueDescriptor<RegExpConstructor, InternalFunction>(exec, ExecState::regExpConstructorTable(exec), this, propertyName, descriptor); +} + JSValue regExpConstructorDollar1(ExecState* exec, const Identifier&, const PropertySlot& slot) { return asRegExpConstructor(slot.slotBase())->getBackref(exec, 1); @@ -329,7 +291,7 @@ JSObject* constructRegExp(ExecState* exec, const ArgList& args) JSValue arg0 = args.at(0); JSValue arg1 = args.at(1); - if (arg0.isObject(&RegExpObject::info)) { + if (arg0.inherits(&RegExpObject::info)) { if (!arg1.isUndefined()) return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another."); return asObject(arg0); diff --git a/JavaScriptCore/runtime/RegExpConstructor.h b/JavaScriptCore/runtime/RegExpConstructor.h index 6823f3f..f9ca9cf 100644 --- a/JavaScriptCore/runtime/RegExpConstructor.h +++ b/JavaScriptCore/runtime/RegExpConstructor.h @@ -22,6 +22,7 @@ #define RegExpConstructor_h #include "InternalFunction.h" +#include "RegExp.h" #include <wtf/OwnPtr.h> namespace JSC { @@ -30,17 +31,40 @@ namespace JSC { class RegExpPrototype; struct RegExpConstructorPrivate; + struct RegExpConstructorPrivate : FastAllocBase { + // Global search cache / settings + RegExpConstructorPrivate() + : lastNumSubPatterns(0) + , multiline(false) + , lastOvectorIndex(0) + { + } + + const Vector<int, 32>& lastOvector() const { return ovector[lastOvectorIndex]; } + Vector<int, 32>& lastOvector() { return ovector[lastOvectorIndex]; } + Vector<int, 32>& tempOvector() { return ovector[lastOvectorIndex ? 0 : 1]; } + void changeLastOvector() { lastOvectorIndex = lastOvectorIndex ? 0 : 1; } + + UString input; + UString lastInput; + Vector<int, 32> ovector[2]; + unsigned lastNumSubPatterns : 30; + bool multiline : 1; + unsigned lastOvectorIndex : 1; + }; + class RegExpConstructor : public InternalFunction { public: - RegExpConstructor(ExecState*, PassRefPtr<Structure>, RegExpPrototype*); + RegExpConstructor(ExecState*, NonNullPassRefPtr<Structure>, RegExpPrototype*); static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType, ImplementsHasInstance)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); static const ClassInfo info; @@ -58,6 +82,9 @@ namespace JSC { JSValue getLeftContext(ExecState*) const; JSValue getRightContext(ExecState*) const; + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | ImplementsHasInstance | InternalFunction::StructureFlags; + private: virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); @@ -77,6 +104,30 @@ namespace JSC { return static_cast<RegExpConstructor*>(asObject(value)); } + /* + To facilitate result caching, exec(), test(), match(), search(), and replace() dipatch regular + expression matching through the performMatch function. We use cached results to calculate, + e.g., RegExp.lastMatch and RegExp.leftParen. + */ + inline void RegExpConstructor::performMatch(RegExp* r, const UString& s, int startOffset, int& position, int& length, int** ovector) + { + position = r->match(s, startOffset, &d->tempOvector()); + + if (ovector) + *ovector = d->tempOvector().data(); + + if (position != -1) { + ASSERT(!d->tempOvector().isEmpty()); + + length = d->tempOvector()[1] - d->tempOvector()[0]; + + d->input = s; + d->lastInput = s; + d->changeLastOvector(); + d->lastNumSubPatterns = r->numSubpatterns(); + } + } + } // namespace JSC #endif // RegExpConstructor_h diff --git a/JavaScriptCore/runtime/RegExpMatchesArray.h b/JavaScriptCore/runtime/RegExpMatchesArray.h index 9ae18b9..829f7cf 100644 --- a/JavaScriptCore/runtime/RegExpMatchesArray.h +++ b/JavaScriptCore/runtime/RegExpMatchesArray.h @@ -44,6 +44,13 @@ namespace JSC { return JSArray::getOwnPropertySlot(exec, propertyName, slot); } + virtual bool getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) + { + if (lazyCreationData()) + fillArrayInstance(exec); + return JSArray::getOwnPropertyDescriptor(exec, propertyName, descriptor); + } + virtual void put(ExecState* exec, const Identifier& propertyName, JSValue v, PutPropertySlot& slot) { if (lazyCreationData()) @@ -72,11 +79,11 @@ namespace JSC { return JSArray::deleteProperty(exec, propertyName); } - virtual void getPropertyNames(ExecState* exec, PropertyNameArray& arr) + virtual void getOwnPropertyNames(ExecState* exec, PropertyNameArray& arr) { if (lazyCreationData()) fillArrayInstance(exec); - JSArray::getPropertyNames(exec, arr); + JSArray::getOwnPropertyNames(exec, arr); } void fillArrayInstance(ExecState*); diff --git a/JavaScriptCore/runtime/RegExpObject.cpp b/JavaScriptCore/runtime/RegExpObject.cpp index 687844e..679d072 100644 --- a/JavaScriptCore/runtime/RegExpObject.cpp +++ b/JavaScriptCore/runtime/RegExpObject.cpp @@ -57,7 +57,7 @@ const ClassInfo RegExpObject::info = { "RegExp", 0, 0, ExecState::regExpTable }; @end */ -RegExpObject::RegExpObject(PassRefPtr<Structure> structure, PassRefPtr<RegExp> regExp) +RegExpObject::RegExpObject(NonNullPassRefPtr<Structure> structure, NonNullPassRefPtr<RegExp> regExp) : JSObject(structure) , d(new RegExpObjectData(regExp, 0)) { @@ -72,6 +72,11 @@ bool RegExpObject::getOwnPropertySlot(ExecState* exec, const Identifier& propert return getStaticValueSlot<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, slot); } +bool RegExpObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticValueDescriptor<RegExpObject, JSObject>(exec, ExecState::regExpTable(exec), this, propertyName, descriptor); +} + JSValue regExpObjectGlobal(ExecState*, const Identifier&, const PropertySlot& slot) { return jsBoolean(asRegExpObject(slot.slotBase())->regExp()->global()); @@ -154,7 +159,7 @@ bool RegExpObject::match(ExecState* exec, const ArgList& args) } int position; - int length; + int length = 0; regExpConstructor->performMatch(d->regExp.get(), input, static_cast<int>(d->lastIndex), position, length); if (position < 0) { d->lastIndex = 0; diff --git a/JavaScriptCore/runtime/RegExpObject.h b/JavaScriptCore/runtime/RegExpObject.h index e83e0ac..3117c86 100644 --- a/JavaScriptCore/runtime/RegExpObject.h +++ b/JavaScriptCore/runtime/RegExpObject.h @@ -28,7 +28,7 @@ namespace JSC { class RegExpObject : public JSObject { public: - RegExpObject(PassRefPtr<Structure>, PassRefPtr<RegExp>); + RegExpObject(NonNullPassRefPtr<Structure>, NonNullPassRefPtr<RegExp>); virtual ~RegExpObject(); void setRegExp(PassRefPtr<RegExp> r) { d->regExp = r; } @@ -41,6 +41,7 @@ namespace JSC { JSValue exec(ExecState*, const ArgList&); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState*, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual const ClassInfo* classInfo() const { return &info; } @@ -48,16 +49,19 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } + protected: + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | JSObject::StructureFlags; + private: bool match(ExecState*, const ArgList&); virtual CallType getCallData(CallData&); struct RegExpObjectData : FastAllocBase { - RegExpObjectData(PassRefPtr<RegExp> regExp, double lastIndex) + RegExpObjectData(NonNullPassRefPtr<RegExp> regExp, double lastIndex) : regExp(regExp) , lastIndex(lastIndex) { diff --git a/JavaScriptCore/runtime/RegExpPrototype.cpp b/JavaScriptCore/runtime/RegExpPrototype.cpp index b1ab889..bbc9e85 100644 --- a/JavaScriptCore/runtime/RegExpPrototype.cpp +++ b/JavaScriptCore/runtime/RegExpPrototype.cpp @@ -22,6 +22,7 @@ #include "RegExpPrototype.h" #include "ArrayPrototype.h" +#include "Error.h" #include "JSArray.h" #include "JSFunction.h" #include "JSObject.h" @@ -45,7 +46,7 @@ static JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState*, JSObject*, JSVa const ClassInfo RegExpPrototype::info = { "RegExpPrototype", 0, 0, 0 }; -RegExpPrototype::RegExpPrototype(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) +RegExpPrototype::RegExpPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure) : JSObject(structure) { putDirectFunctionWithoutTransition(exec, new (exec) NativeFunctionWrapper(exec, prototypeFunctionStructure, 0, exec->propertyNames().compile, regExpProtoFuncCompile), DontEnum); @@ -58,28 +59,28 @@ RegExpPrototype::RegExpPrototype(ExecState* exec, PassRefPtr<Structure> structur JSValue JSC_HOST_CALL regExpProtoFuncTest(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { - if (!thisValue.isObject(&RegExpObject::info)) + if (!thisValue.inherits(&RegExpObject::info)) return throwError(exec, TypeError); return asRegExpObject(thisValue)->test(exec, args); } JSValue JSC_HOST_CALL regExpProtoFuncExec(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { - if (!thisValue.isObject(&RegExpObject::info)) + if (!thisValue.inherits(&RegExpObject::info)) return throwError(exec, TypeError); return asRegExpObject(thisValue)->exec(exec, args); } JSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { - if (!thisValue.isObject(&RegExpObject::info)) + if (!thisValue.inherits(&RegExpObject::info)) return throwError(exec, TypeError); RefPtr<RegExp> regExp; JSValue arg0 = args.at(0); JSValue arg1 = args.at(1); - if (arg0.isObject(&RegExpObject::info)) { + if (arg0.inherits(&RegExpObject::info)) { if (!arg1.isUndefined()) return throwError(exec, TypeError, "Cannot supply flags when constructing one RegExp from another."); regExp = asRegExpObject(arg0)->regExp(); @@ -99,8 +100,8 @@ JSValue JSC_HOST_CALL regExpProtoFuncCompile(ExecState* exec, JSObject*, JSValue JSValue JSC_HOST_CALL regExpProtoFuncToString(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { - if (!thisValue.isObject(&RegExpObject::info)) { - if (thisValue.isObject(&RegExpPrototype::info)) + if (!thisValue.inherits(&RegExpObject::info)) { + if (thisValue.inherits(&RegExpPrototype::info)) return jsNontrivialString(exec, "//"); return throwError(exec, TypeError); } diff --git a/JavaScriptCore/runtime/RegExpPrototype.h b/JavaScriptCore/runtime/RegExpPrototype.h index f5db720..d3979bd 100644 --- a/JavaScriptCore/runtime/RegExpPrototype.h +++ b/JavaScriptCore/runtime/RegExpPrototype.h @@ -27,7 +27,7 @@ namespace JSC { class RegExpPrototype : public JSObject { public: - RegExpPrototype(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure); + RegExpPrototype(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; diff --git a/JavaScriptCore/runtime/ScopeChain.cpp b/JavaScriptCore/runtime/ScopeChain.cpp index 5c2edab..981794b 100644 --- a/JavaScriptCore/runtime/ScopeChain.cpp +++ b/JavaScriptCore/runtime/ScopeChain.cpp @@ -36,8 +36,8 @@ void ScopeChainNode::print() const ScopeChainIterator scopeEnd = end(); for (ScopeChainIterator scopeIter = begin(); scopeIter != scopeEnd; ++scopeIter) { JSObject* o = *scopeIter; - PropertyNameArray propertyNames(globalObject()->globalExec()); - o->getPropertyNames(globalObject()->globalExec(), propertyNames); + PropertyNameArray propertyNames(globalObject->globalExec()); + o->getPropertyNames(globalObject->globalExec(), propertyNames); PropertyNameArray::const_iterator propEnd = propertyNames.end(); fprintf(stderr, "----- [scope %p] -----\n", o); @@ -56,7 +56,7 @@ int ScopeChain::localDepth() const int scopeDepth = 0; ScopeChainIterator iter = this->begin(); ScopeChainIterator end = this->end(); - while (!(*iter)->isObject(&JSActivation::info)) { + while (!(*iter)->inherits(&JSActivation::info)) { ++iter; if (iter == end) break; diff --git a/JavaScriptCore/runtime/ScopeChain.h b/JavaScriptCore/runtime/ScopeChain.h index c5e16c9..0b15b67 100644 --- a/JavaScriptCore/runtime/ScopeChain.h +++ b/JavaScriptCore/runtime/ScopeChain.h @@ -33,14 +33,16 @@ namespace JSC { class ScopeChainNode : public FastAllocBase { public: - ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSObject* globalThis) + ScopeChainNode(ScopeChainNode* next, JSObject* object, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis) : next(next) , object(object) , globalData(globalData) + , globalObject(globalObject) , globalThis(globalThis) , refCount(1) { ASSERT(globalData); + ASSERT(globalObject); } #ifndef NDEBUG // Due to the number of subtle and timing dependent bugs that have occurred due @@ -51,6 +53,7 @@ namespace JSC { next = 0; object = 0; globalData = 0; + globalObject = 0; globalThis = 0; } #endif @@ -58,6 +61,7 @@ namespace JSC { ScopeChainNode* next; JSObject* object; JSGlobalData* globalData; + JSGlobalObject* globalObject; JSObject* globalThis; int refCount; @@ -82,9 +86,6 @@ namespace JSC { ScopeChainIterator begin() const; ScopeChainIterator end() const; - JSGlobalObject* globalObject() const; // defined in JSGlobalObject.h - JSObject* globalThisObject() const { return globalThis; } - #ifndef NDEBUG void print() const; #endif @@ -93,7 +94,7 @@ namespace JSC { inline ScopeChainNode* ScopeChainNode::push(JSObject* o) { ASSERT(o); - return new ScopeChainNode(this, o, globalData, globalThis); + return new ScopeChainNode(this, o, globalData, globalObject, globalThis); } inline ScopeChainNode* ScopeChainNode::pop() @@ -163,8 +164,8 @@ namespace JSC { { } - ScopeChain(JSObject* o, JSGlobalData* globalData, JSObject* globalThis) - : m_node(new ScopeChainNode(0, o, globalData, globalThis)) + ScopeChain(JSObject* o, JSGlobalData* globalData, JSGlobalObject* globalObject, JSObject* globalThis) + : m_node(new ScopeChainNode(0, o, globalData, globalObject, globalThis)) { } @@ -203,7 +204,7 @@ namespace JSC { void pop() { m_node = m_node->pop(); } void clear() { m_node->deref(); m_node = 0; } - JSGlobalObject* globalObject() const { return m_node->globalObject(); } + JSGlobalObject* globalObject() const { return m_node->globalObject; } void markAggregate(MarkStack&) const; diff --git a/JavaScriptCore/runtime/SmallStrings.cpp b/JavaScriptCore/runtime/SmallStrings.cpp index 2f92cc1..04701cb 100644 --- a/JavaScriptCore/runtime/SmallStrings.cpp +++ b/JavaScriptCore/runtime/SmallStrings.cpp @@ -82,13 +82,13 @@ SmallStrings::~SmallStrings() { } -void SmallStrings::mark() +void SmallStrings::markChildren(MarkStack& markStack) { - if (m_emptyString && !m_emptyString->marked()) - m_emptyString->markCellDirect(); + if (m_emptyString) + markStack.append(m_emptyString); for (unsigned i = 0; i < numCharactersToStore; ++i) { - if (m_singleCharacterStrings[i] && !m_singleCharacterStrings[i]->marked()) - m_singleCharacterStrings[i]->markCellDirect(); + if (m_singleCharacterStrings[i]) + markStack.append(m_singleCharacterStrings[i]); } } diff --git a/JavaScriptCore/runtime/SmallStrings.h b/JavaScriptCore/runtime/SmallStrings.h index f0dd8df..efecbb0 100644 --- a/JavaScriptCore/runtime/SmallStrings.h +++ b/JavaScriptCore/runtime/SmallStrings.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All Rights Reserved. + * Copyright (C) 2008, 2009 Apple Inc. All Rights Reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -33,7 +33,7 @@ namespace JSC { class JSGlobalData; class JSString; - + class MarkStack; class SmallStringsStorage; class SmallStrings : public Noncopyable { @@ -56,7 +56,7 @@ namespace JSC { UString::Rep* singleCharacterStringRep(unsigned char character); - void mark(); + void markChildren(MarkStack&); unsigned count() const; diff --git a/JavaScriptCore/runtime/StringConstructor.cpp b/JavaScriptCore/runtime/StringConstructor.cpp index 6380445..2f3adbe 100644 --- a/JavaScriptCore/runtime/StringConstructor.cpp +++ b/JavaScriptCore/runtime/StringConstructor.cpp @@ -47,7 +47,7 @@ static JSValue JSC_HOST_CALL stringFromCharCode(ExecState* exec, JSObject*, JSVa ASSERT_CLASS_FITS_IN_CELL(StringConstructor); -StringConstructor::StringConstructor(ExecState* exec, PassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, StringPrototype* stringPrototype) +StringConstructor::StringConstructor(ExecState* exec, NonNullPassRefPtr<Structure> structure, Structure* prototypeFunctionStructure, StringPrototype* stringPrototype) : InternalFunction(&exec->globalData(), structure, Identifier(exec, stringPrototype->classInfo()->className)) { // ECMA 15.5.3.1 String.prototype diff --git a/JavaScriptCore/runtime/StringConstructor.h b/JavaScriptCore/runtime/StringConstructor.h index 7d52c69..e511f7b 100644 --- a/JavaScriptCore/runtime/StringConstructor.h +++ b/JavaScriptCore/runtime/StringConstructor.h @@ -29,7 +29,7 @@ namespace JSC { class StringConstructor : public InternalFunction { public: - StringConstructor(ExecState*, PassRefPtr<Structure>, Structure* prototypeFunctionStructure, StringPrototype*); + StringConstructor(ExecState*, NonNullPassRefPtr<Structure>, Structure* prototypeFunctionStructure, StringPrototype*); virtual ConstructType getConstructData(ConstructData&); virtual CallType getCallData(CallData&); diff --git a/JavaScriptCore/runtime/StringObject.cpp b/JavaScriptCore/runtime/StringObject.cpp index fb44498..f23a20d 100644 --- a/JavaScriptCore/runtime/StringObject.cpp +++ b/JavaScriptCore/runtime/StringObject.cpp @@ -29,19 +29,19 @@ ASSERT_CLASS_FITS_IN_CELL(StringObject); const ClassInfo StringObject::info = { "String", 0, 0, 0 }; -StringObject::StringObject(ExecState* exec, PassRefPtr<Structure> structure) +StringObject::StringObject(ExecState* exec, NonNullPassRefPtr<Structure> structure) : JSWrapperObject(structure) { setInternalValue(jsEmptyString(exec)); } -StringObject::StringObject(PassRefPtr<Structure> structure, JSString* string) +StringObject::StringObject(NonNullPassRefPtr<Structure> structure, JSString* string) : JSWrapperObject(structure) { setInternalValue(string); } -StringObject::StringObject(ExecState* exec, PassRefPtr<Structure> structure, const UString& string) +StringObject::StringObject(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& string) : JSWrapperObject(structure) { setInternalValue(jsString(exec, string)); @@ -61,6 +61,13 @@ bool StringObject::getOwnPropertySlot(ExecState* exec, unsigned propertyName, Pr return JSObject::getOwnPropertySlot(exec, Identifier::from(exec, propertyName), slot); } +bool StringObject::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + if (internalValue()->getStringPropertyDescriptor(exec, propertyName, descriptor)) + return true; + return JSObject::getOwnPropertyDescriptor(exec, propertyName, descriptor); +} + void StringObject::put(ExecState* exec, const Identifier& propertyName, JSValue value, PutPropertySlot& slot) { if (propertyName == exec->propertyNames().length) @@ -72,30 +79,19 @@ bool StringObject::deleteProperty(ExecState* exec, const Identifier& propertyNam { if (propertyName == exec->propertyNames().length) return false; + bool isStrictUInt32; + unsigned i = propertyName.toStrictUInt32(&isStrictUInt32); + if (isStrictUInt32 && internalValue()->canGetIndex(i)) + return false; return JSObject::deleteProperty(exec, propertyName); } -void StringObject::getPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) +void StringObject::getOwnPropertyNames(ExecState* exec, PropertyNameArray& propertyNames) { - int size = internalValue()->value().size(); + int size = internalValue()->length(); for (int i = 0; i < size; ++i) propertyNames.add(Identifier(exec, UString::from(i))); - return JSObject::getPropertyNames(exec, propertyNames); -} - -UString StringObject::toString(ExecState*) const -{ - return internalValue()->value(); -} - -UString StringObject::toThisString(ExecState*) const -{ - return internalValue()->value(); -} - -JSString* StringObject::toThisJSString(ExecState*) -{ - return internalValue(); + return JSObject::getOwnPropertyNames(exec, propertyNames); } } // namespace JSC diff --git a/JavaScriptCore/runtime/StringObject.h b/JavaScriptCore/runtime/StringObject.h index ea3a045..84e1ad2 100644 --- a/JavaScriptCore/runtime/StringObject.h +++ b/JavaScriptCore/runtime/StringObject.h @@ -28,17 +28,18 @@ namespace JSC { class StringObject : public JSWrapperObject { public: - StringObject(ExecState*, PassRefPtr<Structure>); - StringObject(ExecState*, PassRefPtr<Structure>, const UString&); + StringObject(ExecState*, NonNullPassRefPtr<Structure>); + StringObject(ExecState*, NonNullPassRefPtr<Structure>, const UString&); static StringObject* create(ExecState*, JSString*); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); virtual bool getOwnPropertySlot(ExecState*, unsigned propertyName, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual void put(ExecState* exec, const Identifier& propertyName, JSValue, PutPropertySlot&); virtual bool deleteProperty(ExecState*, const Identifier& propertyName); - virtual void getPropertyNames(ExecState*, PropertyNameArray&); + virtual void getOwnPropertyNames(ExecState*, PropertyNameArray&); virtual const ClassInfo* classInfo() const { return &info; } static const JS_EXPORTDATA ClassInfo info; @@ -47,16 +48,12 @@ namespace JSC { static PassRefPtr<Structure> createStructure(JSValue prototype) { - return Structure::create(prototype, TypeInfo(ObjectType)); + return Structure::create(prototype, TypeInfo(ObjectType, StructureFlags)); } protected: - StringObject(PassRefPtr<Structure>, JSString*); - - private: - virtual UString toString(ExecState*) const; - virtual UString toThisString(ExecState*) const; - virtual JSString* toThisJSString(ExecState*); + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | OverridesMarkChildren | OverridesGetPropertyNames | JSWrapperObject::StructureFlags; + StringObject(NonNullPassRefPtr<Structure>, JSString*); }; StringObject* asStringObject(JSValue); diff --git a/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h b/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h index bc5c0a5..69e1939 100644 --- a/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h +++ b/JavaScriptCore/runtime/StringObjectThatMasqueradesAsUndefined.h @@ -37,16 +37,18 @@ namespace JSC { } private: - StringObjectThatMasqueradesAsUndefined(ExecState* exec, PassRefPtr<Structure> structure, const UString& string) + StringObjectThatMasqueradesAsUndefined(ExecState* exec, NonNullPassRefPtr<Structure> structure, const UString& string) : StringObject(exec, structure, string) { } static PassRefPtr<Structure> createStructure(JSValue proto) { - return Structure::create(proto, TypeInfo(ObjectType, MasqueradesAsUndefined)); + return Structure::create(proto, TypeInfo(ObjectType, StructureFlags)); } + static const unsigned StructureFlags = OverridesGetOwnPropertySlot | MasqueradesAsUndefined | OverridesGetPropertyNames | StringObject::StructureFlags; + virtual bool toBoolean(ExecState*) const { return false; } }; diff --git a/JavaScriptCore/runtime/StringPrototype.cpp b/JavaScriptCore/runtime/StringPrototype.cpp index 531a302..32f9e6b 100644 --- a/JavaScriptCore/runtime/StringPrototype.cpp +++ b/JavaScriptCore/runtime/StringPrototype.cpp @@ -23,6 +23,9 @@ #include "StringPrototype.h" #include "CachedCall.h" +#include "Error.h" +#include "Executable.h" +#include "JSGlobalObjectFunctions.h" #include "JSArray.h" #include "JSFunction.h" #include "ObjectPrototype.h" @@ -70,6 +73,10 @@ static JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState*, JSObject*, JSVa static JSValue JSC_HOST_CALL stringProtoFuncAnchor(ExecState*, JSObject*, JSValue, const ArgList&); static JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState*, JSObject*, JSValue, const ArgList&); +static JSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState*, JSObject*, JSValue, const ArgList&); + } #include "StringPrototype.lut.h" @@ -115,11 +122,14 @@ const ClassInfo StringPrototype::info = { "String", &StringObject::info, 0, Exec fontsize stringProtoFuncFontsize DontEnum|Function 1 anchor stringProtoFuncAnchor DontEnum|Function 1 link stringProtoFuncLink DontEnum|Function 1 + trim stringProtoFuncTrim DontEnum|Function 0 + trimLeft stringProtoFuncTrimLeft DontEnum|Function 0 + trimRight stringProtoFuncTrimRight DontEnum|Function 0 @end */ // ECMA 15.5.4 -StringPrototype::StringPrototype(ExecState* exec, PassRefPtr<Structure> structure) +StringPrototype::StringPrototype(ExecState* exec, NonNullPassRefPtr<Structure> structure) : StringObject(exec, structure) { // The constructor will be added later, after StringConstructor has been built @@ -131,6 +141,11 @@ bool StringPrototype::getOwnPropertySlot(ExecState* exec, const Identifier& prop return getStaticFunctionSlot<StringObject>(exec, ExecState::stringTable(exec), this, propertyName, slot); } +bool StringPrototype::getOwnPropertyDescriptor(ExecState* exec, const Identifier& propertyName, PropertyDescriptor& descriptor) +{ + return getStaticFunctionDescriptor<StringObject>(exec, ExecState::stringTable(exec), this, propertyName, descriptor); +} + // ------------------------------ Functions -------------------------- static inline UString substituteBackreferences(const UString& replacement, const UString& source, const int* ovector, RegExp* reg) @@ -209,7 +224,7 @@ static inline int localeCompare(const UString& a, const UString& b) JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue thisValue, const ArgList& args) { JSString* sourceVal = thisValue.toThisJSString(exec); - const UString& source = sourceVal->value(); + const UString& source = sourceVal->value(exec); JSValue pattern = args.at(0); @@ -220,7 +235,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue if (callType == CallTypeNone) replacementString = replacement.toString(exec); - if (pattern.isObject(&RegExpObject::info)) { + if (pattern.inherits(&RegExpObject::info)) { RegExp* reg = asRegExpObject(pattern)->regExp(); bool global = reg->global(); @@ -242,7 +257,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue return jsNull(); while (true) { int matchIndex; - int matchLen; + int matchLen = 0; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) @@ -266,7 +281,8 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue cachedCall.setArgument(i++, sourceVal); cachedCall.setThis(exec->globalThisValue()); - replacements.append(cachedCall.call().toString(cachedCall.newCallFrame())); + JSValue result = cachedCall.call(); + replacements.append(result.toString(cachedCall.newCallFrame(exec))); if (exec->hadException()) break; @@ -283,7 +299,7 @@ JSValue JSC_HOST_CALL stringProtoFuncReplace(ExecState* exec, JSObject*, JSValue } else { do { int matchIndex; - int matchLen; + int matchLen = 0; int* ovector; regExpConstructor->performMatch(reg, source, startPosition, matchIndex, matchLen, &ovector); if (matchIndex < 0) @@ -365,7 +381,7 @@ JSValue JSC_HOST_CALL stringProtoFuncToString(ExecState* exec, JSObject*, JSValu if (thisValue.isString()) return thisValue; - if (thisValue.isObject(&StringObject::info)) + if (thisValue.inherits(&StringObject::info)) return asStringObject(thisValue)->internalValue(); return throwError(exec, TypeError); @@ -454,6 +470,11 @@ JSValue JSC_HOST_CALL stringProtoFuncLastIndexOf(ExecState* exec, JSObject*, JSV dpos = 0; else if (!(dpos <= len)) // true for NaN dpos = len; +#if PLATFORM(SYMBIAN) + // Work around for broken NaN compare operator + else if (isnan(dpos)) + dpos = len; +#endif return jsNumber(exec, s.rfind(u2, static_cast<int>(dpos))); } @@ -466,7 +487,7 @@ JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue t UString u = s; RefPtr<RegExp> reg; RegExpObject* imp = 0; - if (a0.isObject(&RegExpObject::info)) + if (a0.inherits(&RegExpObject::info)) reg = asRegExpObject(a0)->regExp(); else { /* @@ -478,7 +499,7 @@ JSValue JSC_HOST_CALL stringProtoFuncMatch(ExecState* exec, JSObject*, JSValue t } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; - int matchLength; + int matchLength = 0; regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength); if (!(reg->global())) { // case without 'g' flag is handled like RegExp.prototype.exec @@ -516,7 +537,7 @@ JSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue UString u = s; RefPtr<RegExp> reg; - if (a0.isObject(&RegExpObject::info)) + if (a0.inherits(&RegExpObject::info)) reg = asRegExpObject(a0)->regExp(); else { /* @@ -528,7 +549,7 @@ JSValue JSC_HOST_CALL stringProtoFuncSearch(ExecState* exec, JSObject*, JSValue } RegExpConstructor* regExpConstructor = exec->lexicalGlobalObject()->regExpConstructor(); int pos; - int matchLength; + int matchLength = 0; regExpConstructor->performMatch(reg.get(), u, 0, pos, matchLength); return jsNumber(exec, pos); } @@ -568,7 +589,7 @@ JSValue JSC_HOST_CALL stringProtoFuncSplit(ExecState* exec, JSObject*, JSValue t unsigned i = 0; int p0 = 0; unsigned limit = a1.isUndefined() ? 0xFFFFFFFFU : a1.toUInt32(exec); - if (a0.isObject(&RegExpObject::info)) { + if (a0.inherits(&RegExpObject::info)) { RegExp* reg = asRegExpObject(a0)->regExp(); if (s.isEmpty() && reg->match(s, 0) >= 0) { // empty string matched by regexp -> empty array @@ -676,7 +697,7 @@ JSValue JSC_HOST_CALL stringProtoFuncSubstring(ExecState* exec, JSObject*, JSVal JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { JSString* sVal = thisValue.toThisJSString(exec); - const UString& s = sVal->value(); + const UString& s = sVal->value(exec); int sSize = s.size(); if (!sSize) @@ -710,7 +731,7 @@ JSValue JSC_HOST_CALL stringProtoFuncToLowerCase(ExecState* exec, JSObject*, JSV JSValue JSC_HOST_CALL stringProtoFuncToUpperCase(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) { JSString* sVal = thisValue.toThisJSString(exec); - const UString& s = sVal->value(); + const UString& s = sVal->value(exec); int sSize = s.size(); if (!sSize) @@ -821,8 +842,8 @@ JSValue JSC_HOST_CALL stringProtoFuncFontsize(ExecState* exec, JSObject*, JSValu if (a0.getUInt32(smallInteger) && smallInteger <= 9) { unsigned stringSize = s.size(); unsigned bufferSize = 22 + stringSize; - UChar* buffer = static_cast<UChar*>(tryFastMalloc(bufferSize * sizeof(UChar))); - if (!buffer) + UChar* buffer; + if (!tryFastMalloc(bufferSize * sizeof(UChar)).getValue(buffer)) return jsUndefined(); buffer[0] = '<'; buffer[1] = 'f'; @@ -869,8 +890,8 @@ JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue th unsigned linkTextSize = linkText.size(); unsigned stringSize = s.size(); unsigned bufferSize = 15 + linkTextSize + stringSize; - UChar* buffer = static_cast<UChar*>(tryFastMalloc(bufferSize * sizeof(UChar))); - if (!buffer) + UChar* buffer; + if (!tryFastMalloc(bufferSize * sizeof(UChar)).getValue(buffer)) return jsUndefined(); buffer[0] = '<'; buffer[1] = 'a'; @@ -892,4 +913,51 @@ JSValue JSC_HOST_CALL stringProtoFuncLink(ExecState* exec, JSObject*, JSValue th return jsNontrivialString(exec, UString(buffer, bufferSize, false)); } +enum { + TrimLeft = 1, + TrimRight = 2 +}; + +static inline bool isTrimWhitespace(UChar c) +{ + return isStrWhiteSpace(c) || c == 0x200b; +} + +static inline JSValue trimString(ExecState* exec, JSValue thisValue, int trimKind) +{ + UString str = thisValue.toThisString(exec); + int left = 0; + if (trimKind & TrimLeft) { + while (left < str.size() && isTrimWhitespace(str[left])) + left++; + } + int right = str.size(); + if (trimKind & TrimRight) { + while (right > left && isTrimWhitespace(str[right - 1])) + right--; + } + + // Don't gc allocate a new string if we don't have to. + if (left == 0 && right == str.size() && thisValue.isString()) + return thisValue; + + return jsString(exec, str.substr(left, right - left)); +} + +JSValue JSC_HOST_CALL stringProtoFuncTrim(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + return trimString(exec, thisValue, TrimLeft | TrimRight); +} + +JSValue JSC_HOST_CALL stringProtoFuncTrimLeft(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + return trimString(exec, thisValue, TrimLeft); +} + +JSValue JSC_HOST_CALL stringProtoFuncTrimRight(ExecState* exec, JSObject*, JSValue thisValue, const ArgList&) +{ + return trimString(exec, thisValue, TrimRight); +} + + } // namespace JSC diff --git a/JavaScriptCore/runtime/StringPrototype.h b/JavaScriptCore/runtime/StringPrototype.h index 6f5344e..3a6a2a3 100644 --- a/JavaScriptCore/runtime/StringPrototype.h +++ b/JavaScriptCore/runtime/StringPrototype.h @@ -29,9 +29,10 @@ namespace JSC { class StringPrototype : public StringObject { public: - StringPrototype(ExecState*, PassRefPtr<Structure>); + StringPrototype(ExecState*, NonNullPassRefPtr<Structure>); virtual bool getOwnPropertySlot(ExecState*, const Identifier& propertyName, PropertySlot&); + virtual bool getOwnPropertyDescriptor(ExecState*, const Identifier&, PropertyDescriptor&); virtual const ClassInfo* classInfo() const { return &info; } static const ClassInfo info; diff --git a/JavaScriptCore/runtime/Structure.cpp b/JavaScriptCore/runtime/Structure.cpp index 5dfd919..e4c9ac3 100644 --- a/JavaScriptCore/runtime/Structure.cpp +++ b/JavaScriptCore/runtime/Structure.cpp @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -28,9 +28,10 @@ #include "Identifier.h" #include "JSObject.h" +#include "JSPropertyNameIterator.h" +#include "Lookup.h" #include "PropertyNameArray.h" #include "StructureChain.h" -#include "Lookup.h" #include <wtf/RefCountedLeakCounter.h> #include <wtf/RefPtr.h> @@ -76,6 +77,8 @@ static HashSet<Structure*>& ignoreSet = *(new HashSet<Structure*>); static HashSet<Structure*>& liveStructureSet = *(new HashSet<Structure*>); #endif +static int comparePropertyMapEntryIndices(const void* a, const void* b); + void Structure::dumpStatistics() { #if DUMP_STRUCTURE_ID_STATISTICS @@ -127,17 +130,14 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo) , m_propertyTable(0) , m_propertyStorageCapacity(JSObject::inlineStorageCapacity) , m_offset(noOffset) - , m_isDictionary(false) + , m_dictionaryKind(NoneDictionaryKind) , m_isPinnedPropertyTable(false) , m_hasGetterSetterProperties(false) - , m_usingSingleTransitionSlot(true) , m_attributesInPrevious(0) { ASSERT(m_prototype); ASSERT(m_prototype.isObject() || m_prototype.isNull()); - m_transitions.singleTransition = 0; - #ifndef NDEBUG #if ENABLE(JSC_MULTIPLE_THREADS) MutexLocker protect(ignoreSetMutex); @@ -156,19 +156,15 @@ Structure::Structure(JSValue prototype, const TypeInfo& typeInfo) Structure::~Structure() { if (m_previous) { - if (m_previous->m_usingSingleTransitionSlot) { - m_previous->m_transitions.singleTransition = 0; - } else { - ASSERT(m_previous->m_transitions.table->contains(make_pair(m_nameInPrevious.get(), make_pair(m_attributesInPrevious, m_specificValueInPrevious)))); - m_previous->m_transitions.table->remove(make_pair(m_nameInPrevious.get(), make_pair(m_attributesInPrevious, m_specificValueInPrevious))); - } - } - - if (m_cachedPropertyNameArrayData) - m_cachedPropertyNameArrayData->setCachedStructure(0); + if (m_nameInPrevious) + m_previous->table.remove(make_pair(m_nameInPrevious.get(), m_attributesInPrevious), m_specificValueInPrevious); + else + m_previous->table.removeAnonymousSlotTransition(m_anonymousSlotsInPrevious); - if (!m_usingSingleTransitionSlot) - delete m_transitions.table; + } + + if (m_enumerationCache) + m_enumerationCache->setCachedStructure(0); if (m_propertyTable) { unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; @@ -279,49 +275,16 @@ void Structure::materializePropertyMap() for (ptrdiff_t i = structures.size() - 2; i >= 0; --i) { structure = structures[i]; + if (!structure->m_nameInPrevious) { + m_propertyTable->anonymousSlotCount += structure->m_anonymousSlotsInPrevious; + continue; + } structure->m_nameInPrevious->ref(); PropertyMapEntry entry(structure->m_nameInPrevious.get(), structure->m_offset, structure->m_attributesInPrevious, structure->m_specificValueInPrevious, ++m_propertyTable->lastIndexUsed); insertIntoPropertyMapHashTable(entry); } } -void Structure::getEnumerablePropertyNames(ExecState* exec, PropertyNameArray& propertyNames, JSObject* baseObject) -{ - bool shouldCache = propertyNames.shouldCache() && !(propertyNames.size() || m_isDictionary); - - if (shouldCache && m_cachedPropertyNameArrayData) { - if (m_cachedPropertyNameArrayData->cachedPrototypeChain() == prototypeChain(exec)) { - propertyNames.setData(m_cachedPropertyNameArrayData); - return; - } - clearEnumerationCache(); - } - - getEnumerableNamesFromPropertyTable(propertyNames); - getEnumerableNamesFromClassInfoTable(exec, baseObject->classInfo(), propertyNames); - - if (m_prototype.isObject()) { - propertyNames.setShouldCache(false); // No need for our prototypes to waste memory on caching, since they're not being enumerated directly. - asObject(m_prototype)->getPropertyNames(exec, propertyNames); - } - - if (shouldCache) { - StructureChain* protoChain = prototypeChain(exec); - m_cachedPropertyNameArrayData = propertyNames.data(); - if (!protoChain->isCacheable()) - return; - m_cachedPropertyNameArrayData->setCachedPrototypeChain(protoChain); - m_cachedPropertyNameArrayData->setCachedStructure(this); - } -} - -void Structure::clearEnumerationCache() -{ - if (m_cachedPropertyNameArrayData) - m_cachedPropertyNameArrayData->setCachedStructure(0); - m_cachedPropertyNameArrayData.clear(); -} - void Structure::growPropertyStorageCapacity() { if (m_propertyStorageCapacity == JSObject::inlineStorageCapacity) @@ -336,7 +299,7 @@ void Structure::despecifyDictionaryFunction(const Identifier& propertyName) materializePropertyMapIfNecessary(); - ASSERT(m_isDictionary); + ASSERT(isDictionary()); ASSERT(m_propertyTable); unsigned i = rep->computedHash(); @@ -378,25 +341,13 @@ void Structure::despecifyDictionaryFunction(const Identifier& propertyName) PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) { - ASSERT(!structure->m_isDictionary); + ASSERT(!structure->isDictionary()); ASSERT(structure->typeInfo().type() == ObjectType); - if (structure->m_usingSingleTransitionSlot) { - Structure* existingTransition = structure->m_transitions.singleTransition; - if (existingTransition && existingTransition->m_nameInPrevious.get() == propertyName.ustring().rep() - && existingTransition->m_attributesInPrevious == attributes - && existingTransition->m_specificValueInPrevious == specificValue) { - - ASSERT(structure->m_transitions.singleTransition->m_offset != noOffset); - offset = structure->m_transitions.singleTransition->m_offset; - return existingTransition; - } - } else { - if (Structure* existingTransition = structure->m_transitions.table->get(make_pair(propertyName.ustring().rep(), make_pair(attributes, specificValue)))) { - ASSERT(existingTransition->m_offset != noOffset); - offset = existingTransition->m_offset; - return existingTransition; - } + if (Structure* existingTransition = structure->table.get(make_pair(propertyName.ustring().rep(), attributes), specificValue)) { + ASSERT(existingTransition->m_offset != noOffset); + offset = existingTransition->m_offset; + return existingTransition; } return 0; @@ -404,12 +355,12 @@ PassRefPtr<Structure> Structure::addPropertyTransitionToExistingStructure(Struct PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset) { - ASSERT(!structure->m_isDictionary); + ASSERT(!structure->isDictionary()); ASSERT(structure->typeInfo().type() == ObjectType); ASSERT(!Structure::addPropertyTransitionToExistingStructure(structure, propertyName, attributes, specificValue, offset)); if (structure->transitionCount() > s_maxTransitionLength) { - RefPtr<Structure> transition = toDictionaryTransition(structure); + RefPtr<Structure> transition = toCacheableDictionaryTransition(structure); ASSERT(structure != transition); offset = transition->put(propertyName, attributes, specificValue); if (transition->propertyStorageSize() > transition->propertyStorageCapacity()) @@ -426,6 +377,7 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con transition->m_specificValueInPrevious = specificValue; transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; if (structure->m_propertyTable) { if (structure->m_isPinnedPropertyTable) @@ -447,27 +399,15 @@ PassRefPtr<Structure> Structure::addPropertyTransition(Structure* structure, con transition->m_offset = offset; - if (structure->m_usingSingleTransitionSlot) { - if (!structure->m_transitions.singleTransition) { - structure->m_transitions.singleTransition = transition.get(); - return transition.release(); - } - - Structure* existingTransition = structure->m_transitions.singleTransition; - structure->m_usingSingleTransitionSlot = false; - StructureTransitionTable* transitionTable = new StructureTransitionTable; - structure->m_transitions.table = transitionTable; - transitionTable->add(make_pair(existingTransition->m_nameInPrevious.get(), make_pair(existingTransition->m_attributesInPrevious, existingTransition->m_specificValueInPrevious)), existingTransition); - } - structure->m_transitions.table->add(make_pair(propertyName.ustring().rep(), make_pair(attributes, specificValue)), transition.get()); + structure->table.add(make_pair(propertyName.ustring().rep(), attributes), transition.get(), specificValue); return transition.release(); } PassRefPtr<Structure> Structure::removePropertyTransition(Structure* structure, const Identifier& propertyName, size_t& offset) { - ASSERT(!structure->m_isDictionary); + ASSERT(!structure->isUncacheableDictionary()); - RefPtr<Structure> transition = toDictionaryTransition(structure); + RefPtr<Structure> transition = toUncacheableDictionaryTransition(structure); offset = transition->remove(propertyName); @@ -480,6 +420,7 @@ PassRefPtr<Structure> Structure::changePrototypeTransition(Structure* structure, transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; // Don't set m_offset, as one can not transition to this. @@ -496,6 +437,7 @@ PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structur transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; // Don't set m_offset, as one can not transition to this. @@ -509,11 +451,54 @@ PassRefPtr<Structure> Structure::despecifyFunctionTransition(Structure* structur return transition.release(); } +PassRefPtr<Structure> Structure::addAnonymousSlotsTransition(Structure* structure, unsigned count) +{ + if (Structure* transition = structure->table.getAnonymousSlotTransition(count)) { + ASSERT(transition->storedPrototype() == structure->storedPrototype()); + return transition; + } + ASSERT(count); + ASSERT(count < ((1<<6) - 2)); + RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo()); + + transition->m_cachedPrototypeChain = structure->m_cachedPrototypeChain; + transition->m_previous = structure; + transition->m_nameInPrevious = 0; + transition->m_attributesInPrevious = 0; + transition->m_anonymousSlotsInPrevious = count; + transition->m_specificValueInPrevious = 0; + transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; + transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; + + if (structure->m_propertyTable) { + if (structure->m_isPinnedPropertyTable) + transition->m_propertyTable = structure->copyPropertyTable(); + else { + transition->m_propertyTable = structure->m_propertyTable; + structure->m_propertyTable = 0; + } + } else { + if (structure->m_previous) + transition->materializePropertyMap(); + else + transition->createPropertyMapHashTable(); + } + + transition->addAnonymousSlots(count); + if (transition->propertyStorageSize() > transition->propertyStorageCapacity()) + transition->growPropertyStorageCapacity(); + + structure->table.addAnonymousSlotTransition(count, transition.get()); + return transition.release(); +} + PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure) { RefPtr<Structure> transition = create(structure->storedPrototype(), structure->typeInfo()); transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = transition->m_hasGetterSetterProperties; + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; // Don't set m_offset, as one can not transition to this. @@ -524,62 +509,98 @@ PassRefPtr<Structure> Structure::getterSetterTransition(Structure* structure) return transition.release(); } -PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure) +PassRefPtr<Structure> Structure::toDictionaryTransition(Structure* structure, DictionaryKind kind) { - ASSERT(!structure->m_isDictionary); - + ASSERT(!structure->isUncacheableDictionary()); + RefPtr<Structure> transition = create(structure->m_prototype, structure->typeInfo()); - transition->m_isDictionary = true; + transition->m_dictionaryKind = kind; transition->m_propertyStorageCapacity = structure->m_propertyStorageCapacity; transition->m_hasGetterSetterProperties = structure->m_hasGetterSetterProperties; - + transition->m_hasNonEnumerableProperties = structure->m_hasNonEnumerableProperties; + structure->materializePropertyMapIfNecessary(); transition->m_propertyTable = structure->copyPropertyTable(); transition->m_isPinnedPropertyTable = true; - + return transition.release(); } -PassRefPtr<Structure> Structure::fromDictionaryTransition(Structure* structure) +PassRefPtr<Structure> Structure::toCacheableDictionaryTransition(Structure* structure) { - ASSERT(structure->m_isDictionary); + return toDictionaryTransition(structure, CachedDictionaryKind); +} - // Since dictionary Structures are not shared, and no opcodes specialize - // for them, we don't need to allocate a new Structure when transitioning - // to non-dictionary status. +PassRefPtr<Structure> Structure::toUncacheableDictionaryTransition(Structure* structure) +{ + return toDictionaryTransition(structure, UncachedDictionaryKind); +} - // FIMXE: We can make this more efficient by canonicalizing the Structure (draining the - // deleted offsets vector) before transitioning from dictionary. - if (!structure->m_propertyTable || !structure->m_propertyTable->deletedOffsets || structure->m_propertyTable->deletedOffsets->isEmpty()) - structure->m_isDictionary = false; +PassRefPtr<Structure> Structure::flattenDictionaryStructure(JSObject* object) +{ + ASSERT(isDictionary()); + if (isUncacheableDictionary()) { + ASSERT(m_propertyTable); + Vector<PropertyMapEntry*> sortedPropertyEntries(m_propertyTable->keyCount); + PropertyMapEntry** p = sortedPropertyEntries.data(); + unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; + for (unsigned i = 1; i <= entryCount; i++) { + if (m_propertyTable->entries()[i].key) + *p++ = &m_propertyTable->entries()[i]; + } + size_t propertyCount = p - sortedPropertyEntries.data(); + qsort(sortedPropertyEntries.data(), propertyCount, sizeof(PropertyMapEntry*), comparePropertyMapEntryIndices); + sortedPropertyEntries.resize(propertyCount); + + // We now have the properties currently defined on this object + // in the order that they are expected to be in, but we need to + // reorder the storage, so we have to copy the current values out + Vector<JSValue> values(propertyCount); + unsigned anonymousSlotCount = m_propertyTable->anonymousSlotCount; + for (unsigned i = 0; i < propertyCount; i++) { + PropertyMapEntry* entry = sortedPropertyEntries[i]; + values[i] = object->getDirectOffset(entry->offset); + // Update property table to have the new property offsets + entry->offset = anonymousSlotCount + i; + entry->index = i; + } + + // Copy the original property values into their final locations + for (unsigned i = 0; i < propertyCount; i++) + object->putDirectOffset(anonymousSlotCount + i, values[i]); + + if (m_propertyTable->deletedOffsets) { + delete m_propertyTable->deletedOffsets; + m_propertyTable->deletedOffsets = 0; + } + } - return structure; + m_dictionaryKind = NoneDictionaryKind; + return this; } size_t Structure::addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue) { - ASSERT(!m_transitions.singleTransition); - + ASSERT(!m_enumerationCache); materializePropertyMapIfNecessary(); m_isPinnedPropertyTable = true; + size_t offset = put(propertyName, attributes, specificValue); if (propertyStorageSize() > propertyStorageCapacity()) growPropertyStorageCapacity(); - clearEnumerationCache(); return offset; } size_t Structure::removePropertyWithoutTransition(const Identifier& propertyName) { - ASSERT(!m_transitions.singleTransition); - ASSERT(m_isDictionary); + ASSERT(isUncacheableDictionary()); + ASSERT(!m_enumerationCache); materializePropertyMapIfNecessary(); m_isPinnedPropertyTable = true; size_t offset = remove(propertyName); - clearEnumerationCache(); return offset; } @@ -636,6 +657,7 @@ PropertyMapHashTable* Structure::copyPropertyTable() if (m_propertyTable->deletedOffsets) newTable->deletedOffsets = new Vector<unsigned>(*m_propertyTable->deletedOffsets); + newTable->anonymousSlotCount = m_propertyTable->anonymousSlotCount; return newTable; } @@ -744,6 +766,9 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel checkConsistency(); + if (attributes & DontEnum) + m_hasNonEnumerableProperties = true; + UString::Rep* rep = propertyName._ustring.rep(); if (!m_propertyTable) @@ -815,7 +840,7 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel newOffset = m_propertyTable->deletedOffsets->last(); m_propertyTable->deletedOffsets->removeLast(); } else - newOffset = m_propertyTable->keyCount; + newOffset = m_propertyTable->keyCount + m_propertyTable->anonymousSlotCount; m_propertyTable->entries()[entryIndex - 1].offset = newOffset; ++m_propertyTable->keyCount; @@ -827,6 +852,16 @@ size_t Structure::put(const Identifier& propertyName, unsigned attributes, JSCel return newOffset; } +void Structure::addAnonymousSlots(unsigned count) +{ + m_propertyTable->anonymousSlotCount += count; +} + +bool Structure::hasTransition(UString::Rep* rep, unsigned attributes) +{ + return table.hasTransition(make_pair(rep, attributes)); +} + size_t Structure::remove(const Identifier& propertyName) { ASSERT(!propertyName.isNull()); @@ -980,6 +1015,7 @@ void Structure::rehashPropertyMapHashTable(unsigned newTableSize) m_propertyTable = static_cast<PropertyMapHashTable*>(fastZeroedMalloc(PropertyMapHashTable::allocationSize(newTableSize))); m_propertyTable->size = newTableSize; m_propertyTable->sizeMask = newTableSize - 1; + m_propertyTable->anonymousSlotCount = oldTable->anonymousSlotCount; unsigned lastIndexUsed = 0; unsigned entryCount = oldTable->keyCount + oldTable->deletedSentinelCount; @@ -997,7 +1033,7 @@ void Structure::rehashPropertyMapHashTable(unsigned newTableSize) checkConsistency(); } -static int comparePropertyMapEntryIndices(const void* a, const void* b) +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; @@ -1008,7 +1044,7 @@ static int comparePropertyMapEntryIndices(const void* a, const void* b) return 0; } -void Structure::getEnumerableNamesFromPropertyTable(PropertyNameArray& propertyNames) +void Structure::getEnumerablePropertyNames(PropertyNameArray& propertyNames) { materializePropertyMapIfNecessary(); if (!m_propertyTable) @@ -1019,6 +1055,7 @@ void Structure::getEnumerableNamesFromPropertyTable(PropertyNameArray& propertyN int i = 0; unsigned entryCount = m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; for (unsigned k = 1; k <= entryCount; k++) { + ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[k].attributes & DontEnum)); if (m_propertyTable->entries()[k].key && !(m_propertyTable->entries()[k].attributes & DontEnum)) { PropertyMapEntry* value = &m_propertyTable->entries()[k]; int j; @@ -1065,25 +1102,6 @@ void Structure::getEnumerableNamesFromPropertyTable(PropertyNameArray& propertyN } } -void Structure::getEnumerableNamesFromClassInfoTable(ExecState* exec, const ClassInfo* classInfo, PropertyNameArray& propertyNames) -{ - // Add properties from the static hashtables of properties - for (; classInfo; classInfo = classInfo->parentClass) { - const HashTable* table = classInfo->propHashTable(exec); - if (!table) - continue; - table->initializeIfNeeded(exec); - ASSERT(table->table); - - int hashSizeMask = table->compactSize - 1; - const HashEntry* entry = table->table; - for (int i = 0; i <= hashSizeMask; ++i, ++entry) { - if (entry->key() && !(entry->attributes() & DontEnum)) - propertyNames.add(entry->key()); - } - } -} - #if DO_PROPERTYMAP_CONSTENCY_CHECK void Structure::checkConsistency() @@ -1125,6 +1143,7 @@ void Structure::checkConsistency() unsigned nonEmptyEntryCount = 0; for (unsigned c = 1; c <= m_propertyTable->keyCount + m_propertyTable->deletedSentinelCount; ++c) { + ASSERT(m_hasNonEnumerableProperties || !(m_propertyTable->entries()[c].attributes & DontEnum)); UString::Rep* rep = m_propertyTable->entries()[c].key; if (!rep) continue; diff --git a/JavaScriptCore/runtime/Structure.h b/JavaScriptCore/runtime/Structure.h index f3a0c7c..c6b7d91 100644 --- a/JavaScriptCore/runtime/Structure.h +++ b/JavaScriptCore/runtime/Structure.h @@ -29,11 +29,12 @@ #include "Identifier.h" #include "JSType.h" #include "JSValue.h" -#include "MarkStack.h" #include "PropertyMapHashTable.h" +#include "PropertyNameArray.h" +#include "Protect.h" #include "StructureChain.h" #include "StructureTransitionTable.h" -#include "TypeInfo.h" +#include "JSTypeInfo.h" #include "UString.h" #include <wtf/PassRefPtr.h> #include <wtf/RefCounted.h> @@ -46,12 +47,14 @@ namespace JSC { + class MarkStack; class PropertyNameArray; class PropertyNameArrayData; class Structure : public RefCounted<Structure> { public: friend class JIT; + friend class StructureTransitionTable; static PassRefPtr<Structure> create(JSValue prototype, const TypeInfo& typeInfo) { return adoptRef(new Structure(prototype, typeInfo)); @@ -66,24 +69,23 @@ namespace JSC { static PassRefPtr<Structure> addPropertyTransitionToExistingStructure(Structure*, const Identifier& propertyName, unsigned attributes, JSCell* specificValue, size_t& offset); static PassRefPtr<Structure> removePropertyTransition(Structure*, const Identifier& propertyName, size_t& offset); static PassRefPtr<Structure> changePrototypeTransition(Structure*, JSValue prototype); - static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&); + static PassRefPtr<Structure> despecifyFunctionTransition(Structure*, const Identifier&); + static PassRefPtr<Structure> addAnonymousSlotsTransition(Structure*, unsigned count); static PassRefPtr<Structure> getterSetterTransition(Structure*); - static PassRefPtr<Structure> toDictionaryTransition(Structure*); - static PassRefPtr<Structure> fromDictionaryTransition(Structure*); + static PassRefPtr<Structure> toCacheableDictionaryTransition(Structure*); + static PassRefPtr<Structure> toUncacheableDictionaryTransition(Structure*); - ~Structure(); + PassRefPtr<Structure> flattenDictionaryStructure(JSObject*); - void markAggregate(MarkStack& markStack) - { - markStack.append(m_prototype); - } + ~Structure(); // These should be used with caution. size_t addPropertyWithoutTransition(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); size_t removePropertyWithoutTransition(const Identifier& propertyName); void setPrototypeWithoutTransition(JSValue prototype) { m_prototype = prototype; } - - bool isDictionary() const { return m_isDictionary; } + + bool isDictionary() const { return m_dictionaryKind != NoneDictionaryKind; } + bool isUncacheableDictionary() const { return m_dictionaryKind == UncachedDictionaryKind; } const TypeInfo& typeInfo() const { return m_typeInfo; } @@ -94,8 +96,8 @@ namespace JSC { Structure* previousID() const { return m_previous.get(); } void growPropertyStorageCapacity(); - size_t propertyStorageCapacity() const { return m_propertyStorageCapacity; } - size_t propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; } + unsigned propertyStorageCapacity() const { return m_propertyStorageCapacity; } + unsigned propertyStorageSize() const { return m_propertyTable ? m_propertyTable->keyCount + m_propertyTable->anonymousSlotCount + (m_propertyTable->deletedOffsets ? m_propertyTable->deletedOffsets->size() : 0) : m_offset + 1; } bool isUsingInlineStorage() const; size_t get(const Identifier& propertyName); @@ -103,26 +105,47 @@ namespace JSC { size_t get(const Identifier& propertyName, unsigned& attributes, JSCell*& specificValue) { ASSERT(!propertyName.isNull()); - return get(propertyName._ustring.rep(), attributes, specificValue); + return get(propertyName.ustring().rep(), attributes, specificValue); + } + bool transitionedFor(const JSCell* specificValue) + { + return m_specificValueInPrevious == specificValue; + } + bool hasTransition(UString::Rep*, unsigned attributes); + bool hasTransition(const Identifier& propertyName, unsigned attributes) + { + return hasTransition(propertyName._ustring.rep(), attributes); } - - void getEnumerablePropertyNames(ExecState*, PropertyNameArray&, JSObject*); bool hasGetterSetterProperties() const { return m_hasGetterSetterProperties; } void setHasGetterSetterProperties(bool hasGetterSetterProperties) { m_hasGetterSetterProperties = hasGetterSetterProperties; } + bool hasNonEnumerableProperties() const { return m_hasNonEnumerableProperties; } + + bool hasAnonymousSlots() const { return m_propertyTable && m_propertyTable->anonymousSlotCount; } + bool isEmpty() const { return m_propertyTable ? !m_propertyTable->keyCount : m_offset == noOffset; } JSCell* specificValue() { return m_specificValueInPrevious; } void despecifyDictionaryFunction(const Identifier& propertyName); + void setEnumerationCache(JSPropertyNameIterator* enumerationCache); // Defined in JSPropertyNameIterator.h. + JSPropertyNameIterator* enumerationCache() { return m_enumerationCache.get(); } + void getEnumerablePropertyNames(PropertyNameArray&); + private: Structure(JSValue prototype, const TypeInfo&); + + typedef enum { + NoneDictionaryKind = 0, + CachedDictionaryKind = 1, + UncachedDictionaryKind = 2 + } DictionaryKind; + static PassRefPtr<Structure> toDictionaryTransition(Structure*, DictionaryKind); size_t put(const Identifier& propertyName, unsigned attributes, JSCell* specificValue); size_t remove(const Identifier& propertyName); - void getEnumerableNamesFromPropertyTable(PropertyNameArray&); - void getEnumerableNamesFromClassInfoTable(ExecState*, const ClassInfo*, PropertyNameArray&); + void addAnonymousSlots(unsigned slotCount); void expandPropertyMapHashTable(); void rehashPropertyMapHashTable(); @@ -143,8 +166,6 @@ namespace JSC { materializePropertyMap(); } - void clearEnumerationCache(); - signed char transitionCount() const { // Since the number of transitions is always the same as m_offset, we keep the size of Structure down by not storing both. @@ -166,25 +187,30 @@ namespace JSC { RefPtr<Structure> m_previous; RefPtr<UString::Rep> m_nameInPrevious; - - union { - Structure* singleTransition; - StructureTransitionTable* table; - } m_transitions; JSCell* m_specificValueInPrevious; - RefPtr<PropertyNameArrayData> m_cachedPropertyNameArrayData; + StructureTransitionTable table; + + ProtectedPtr<JSPropertyNameIterator> m_enumerationCache; PropertyMapHashTable* m_propertyTable; - size_t m_propertyStorageCapacity; + uint32_t m_propertyStorageCapacity; signed char m_offset; - bool m_isDictionary : 1; + unsigned m_dictionaryKind : 2; bool m_isPinnedPropertyTable : 1; bool m_hasGetterSetterProperties : 1; - bool m_usingSingleTransitionSlot : 1; + bool m_hasNonEnumerableProperties : 1; +#if COMPILER(WINSCW) + // Workaround for Symbian WINSCW compiler that cannot resolve unsigned type of the declared + // bitfield, when used as argument in make_pair() function calls in structure.ccp. + // This bitfield optimization is insignificant for the Symbian emulator target. + unsigned m_attributesInPrevious; +#else unsigned m_attributesInPrevious : 7; +#endif + unsigned m_anonymousSlotsInPrevious : 6; }; inline size_t Structure::get(const Identifier& propertyName) @@ -231,7 +257,58 @@ namespace JSC { return m_propertyTable->entries()[entryIndex - 1].offset; } } + + bool StructureTransitionTable::contains(const StructureTransitionTableHash::Key& key, JSCell* specificValue) + { + if (usingSingleTransitionSlot()) { + Structure* existingTransition = singleTransition(); + return existingTransition && existingTransition->m_nameInPrevious.get() == key.first + && existingTransition->m_attributesInPrevious == key.second + && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0); + } + TransitionTable::iterator find = table()->find(key); + if (find == table()->end()) + return false; + + return find->second.first || find->second.second->transitionedFor(specificValue); + } + + Structure* StructureTransitionTable::get(const StructureTransitionTableHash::Key& key, JSCell* specificValue) const + { + if (usingSingleTransitionSlot()) { + Structure* existingTransition = singleTransition(); + if (existingTransition && existingTransition->m_nameInPrevious.get() == key.first + && existingTransition->m_attributesInPrevious == key.second + && (existingTransition->m_specificValueInPrevious == specificValue || existingTransition->m_specificValueInPrevious == 0)) + return existingTransition; + return 0; + } + + Transition transition = table()->get(key); + if (transition.second && transition.second->transitionedFor(specificValue)) + return transition.second; + return transition.first; + } + bool StructureTransitionTable::hasTransition(const StructureTransitionTableHash::Key& key) const + { + if (usingSingleTransitionSlot()) { + Structure* transition = singleTransition(); + return transition && transition->m_nameInPrevious == key.first + && transition->m_attributesInPrevious == key.second; + } + return table()->contains(key); + } + + void StructureTransitionTable::reifySingleTransition() + { + ASSERT(usingSingleTransitionSlot()); + Structure* existingTransition = singleTransition(); + TransitionTable* transitionTable = new TransitionTable; + setTransitionTable(transitionTable); + if (existingTransition) + add(std::make_pair(existingTransition->m_nameInPrevious.get(), existingTransition->m_attributesInPrevious), existingTransition, existingTransition->m_specificValueInPrevious); + } } // namespace JSC #endif // Structure_h diff --git a/JavaScriptCore/runtime/StructureChain.cpp b/JavaScriptCore/runtime/StructureChain.cpp index 85049b1..085876c 100644 --- a/JavaScriptCore/runtime/StructureChain.cpp +++ b/JavaScriptCore/runtime/StructureChain.cpp @@ -46,15 +46,4 @@ StructureChain::StructureChain(Structure* head) m_vector[i] = 0; } -bool StructureChain::isCacheable() const -{ - uint32_t i = 0; - - while (m_vector[i]) { - if (m_vector[i++]->isDictionary()) - return false; - } - return true; -} - } // namespace JSC diff --git a/JavaScriptCore/runtime/StructureChain.h b/JavaScriptCore/runtime/StructureChain.h index c48749d..816b66d 100644 --- a/JavaScriptCore/runtime/StructureChain.h +++ b/JavaScriptCore/runtime/StructureChain.h @@ -36,10 +36,11 @@ namespace JSC { class Structure; class StructureChain : public RefCounted<StructureChain> { + friend class JIT; + public: static PassRefPtr<StructureChain> create(Structure* head) { return adoptRef(new StructureChain(head)); } RefPtr<Structure>* head() { return m_vector.get(); } - bool isCacheable() const; private: StructureChain(Structure* head); diff --git a/JavaScriptCore/runtime/StructureTransitionTable.h b/JavaScriptCore/runtime/StructureTransitionTable.h index 804cbeb..0fa7b73 100644 --- a/JavaScriptCore/runtime/StructureTransitionTable.h +++ b/JavaScriptCore/runtime/StructureTransitionTable.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2008 Apple Inc. All rights reserved. + * Copyright (C) 2008, 2009 Apple Inc. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -30,6 +30,8 @@ #include <wtf/HashFunctions.h> #include <wtf/HashMap.h> #include <wtf/HashTraits.h> +#include <wtf/PtrAndFlags.h> +#include <wtf/OwnPtr.h> #include <wtf/RefPtr.h> namespace JSC { @@ -37,7 +39,7 @@ namespace JSC { class Structure; struct StructureTransitionTableHash { - typedef std::pair<RefPtr<UString::Rep>, std::pair<unsigned, JSCell*> > Key; + typedef std::pair<RefPtr<UString::Rep>, unsigned> Key; static unsigned hash(const Key& p) { return p.first->computedHash(); @@ -53,20 +55,159 @@ namespace JSC { struct StructureTransitionTableHashTraits { typedef WTF::HashTraits<RefPtr<UString::Rep> > FirstTraits; - typedef WTF::GenericHashTraits<unsigned> SecondFirstTraits; - typedef WTF::GenericHashTraits<JSCell*> SecondSecondTraits; - typedef std::pair<FirstTraits::TraitType, std::pair<SecondFirstTraits::TraitType, SecondSecondTraits::TraitType> > TraitType; + typedef WTF::GenericHashTraits<unsigned> SecondTraits; + typedef std::pair<FirstTraits::TraitType, SecondTraits::TraitType > TraitType; - static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondFirstTraits::emptyValueIsZero && SecondSecondTraits::emptyValueIsZero; - static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), std::make_pair(SecondFirstTraits::emptyValue(), SecondSecondTraits::emptyValue())); } + static const bool emptyValueIsZero = FirstTraits::emptyValueIsZero && SecondTraits::emptyValueIsZero; + static TraitType emptyValue() { return std::make_pair(FirstTraits::emptyValue(), SecondTraits::emptyValue()); } - static const bool needsDestruction = FirstTraits::needsDestruction || SecondFirstTraits::needsDestruction || SecondSecondTraits::needsDestruction; + static const bool needsDestruction = FirstTraits::needsDestruction || SecondTraits::needsDestruction; static void constructDeletedValue(TraitType& slot) { FirstTraits::constructDeletedValue(slot.first); } static bool isDeletedValue(const TraitType& value) { return FirstTraits::isDeletedValue(value.first); } }; - typedef HashMap<StructureTransitionTableHash::Key, Structure*, StructureTransitionTableHash, StructureTransitionTableHashTraits> StructureTransitionTable; + class StructureTransitionTable { + typedef std::pair<Structure*, Structure*> Transition; + struct TransitionTable : public HashMap<StructureTransitionTableHash::Key, Transition, StructureTransitionTableHash, StructureTransitionTableHashTraits> { + typedef HashMap<unsigned, Structure*> AnonymousSlotMap; + + void addSlotTransition(unsigned count, Structure* structure) + { + ASSERT(!getSlotTransition(count)); + if (!m_anonymousSlotTable) + m_anonymousSlotTable.set(new AnonymousSlotMap); + m_anonymousSlotTable->add(count, structure); + } + + void removeSlotTransition(unsigned count) + { + ASSERT(getSlotTransition(count)); + m_anonymousSlotTable->remove(count); + } + + Structure* getSlotTransition(unsigned count) + { + if (!m_anonymousSlotTable) + return 0; + + AnonymousSlotMap::iterator find = m_anonymousSlotTable->find(count); + if (find == m_anonymousSlotTable->end()) + return 0; + return find->second; + } + private: + OwnPtr<AnonymousSlotMap> m_anonymousSlotTable; + }; + public: + StructureTransitionTable() { + m_transitions.m_singleTransition.set(0); + m_transitions.m_singleTransition.setFlag(usingSingleSlot); + } + + ~StructureTransitionTable() { + if (!usingSingleTransitionSlot()) + delete table(); + } + + // The contains and get methods accept imprecise matches, so if an unspecialised transition exists + // for the given key they will consider that transition to be a match. If a specialised transition + // exists and it matches the provided specificValue, get will return the specific transition. + inline bool contains(const StructureTransitionTableHash::Key&, JSCell* specificValue); + inline Structure* get(const StructureTransitionTableHash::Key&, JSCell* specificValue) const; + inline bool hasTransition(const StructureTransitionTableHash::Key& key) const; + void remove(const StructureTransitionTableHash::Key& key, JSCell* specificValue) + { + if (usingSingleTransitionSlot()) { + ASSERT(contains(key, specificValue)); + setSingleTransition(0); + return; + } + TransitionTable::iterator find = table()->find(key); + if (!specificValue) + find->second.first = 0; + else + find->second.second = 0; + if (!find->second.first && !find->second.second) + table()->remove(find); + } + void add(const StructureTransitionTableHash::Key& key, Structure* structure, JSCell* specificValue) + { + if (usingSingleTransitionSlot()) { + if (!singleTransition()) { + setSingleTransition(structure); + return; + } + reifySingleTransition(); + } + if (!specificValue) { + TransitionTable::iterator find = table()->find(key); + if (find == table()->end()) + table()->add(key, Transition(structure, 0)); + else + find->second.first = structure; + } else { + // If we're adding a transition to a specific value, then there cannot be + // an existing transition + ASSERT(!table()->contains(key)); + table()->add(key, Transition(0, structure)); + } + } + + Structure* getAnonymousSlotTransition(unsigned count) + { + if (usingSingleTransitionSlot()) + return 0; + return table()->getSlotTransition(count); + } + + void addAnonymousSlotTransition(unsigned count, Structure* structure) + { + if (usingSingleTransitionSlot()) + reifySingleTransition(); + ASSERT(!table()->getSlotTransition(count)); + table()->addSlotTransition(count, structure); + } + + void removeAnonymousSlotTransition(unsigned count) + { + ASSERT(!usingSingleTransitionSlot()); + table()->removeSlotTransition(count); + } + private: + TransitionTable* table() const { ASSERT(!usingSingleTransitionSlot()); return m_transitions.m_table; } + Structure* singleTransition() const { + ASSERT(usingSingleTransitionSlot()); + return m_transitions.m_singleTransition.get(); + } + bool usingSingleTransitionSlot() const { return m_transitions.m_singleTransition.isFlagSet(usingSingleSlot); } + void setSingleTransition(Structure* structure) + { + ASSERT(usingSingleTransitionSlot()); + m_transitions.m_singleTransition.set(structure); + } + + void setTransitionTable(TransitionTable* table) + { + ASSERT(usingSingleTransitionSlot()); +#ifndef NDEBUG + setSingleTransition(0); +#endif + m_transitions.m_table = table; + // This implicitly clears the flag that indicates we're using a single transition + ASSERT(!usingSingleTransitionSlot()); + } + inline void reifySingleTransition(); + + enum UsingSingleSlot { + usingSingleSlot + }; + // Last bit indicates whether we are using the single transition optimisation + union { + TransitionTable* m_table; + PtrAndFlagsBase<Structure, UsingSingleSlot> m_singleTransition; + } m_transitions; + }; } // namespace JSC diff --git a/JavaScriptCore/runtime/SymbolTable.h b/JavaScriptCore/runtime/SymbolTable.h index c00f95a..f5e2669 100644 --- a/JavaScriptCore/runtime/SymbolTable.h +++ b/JavaScriptCore/runtime/SymbolTable.h @@ -121,6 +121,10 @@ namespace JSC { typedef HashMap<RefPtr<UString::Rep>, SymbolTableEntry, IdentifierRepHash, HashTraits<RefPtr<UString::Rep> >, SymbolTableIndexHashTraits> SymbolTable; + class SharedSymbolTable : public SymbolTable, public RefCounted<SharedSymbolTable> + { + }; + } // namespace JSC #endif // SymbolTable_h diff --git a/JavaScriptCore/runtime/TimeoutChecker.cpp b/JavaScriptCore/runtime/TimeoutChecker.cpp index 30ba6e9..2a056c9 100644 --- a/JavaScriptCore/runtime/TimeoutChecker.cpp +++ b/JavaScriptCore/runtime/TimeoutChecker.cpp @@ -35,18 +35,10 @@ #if PLATFORM(DARWIN) #include <mach/mach.h> -#endif - -#if HAVE(SYS_TIME_H) -#include <sys/time.h> -#endif - -#if PLATFORM(WIN_OS) +#elif PLATFORM(WIN_OS) #include <windows.h> -#endif - -#if PLATFORM(QT) -#include <QDateTime> +#else +#include "CurrentTime.h" #endif using namespace std; @@ -75,14 +67,6 @@ static inline unsigned getCPUTime() time += info.system_time.seconds * 1000 + info.system_time.microseconds / 1000; return time; -#elif HAVE(SYS_TIME_H) - // FIXME: This should probably use getrusage with the RUSAGE_THREAD flag. - struct timeval tv; - gettimeofday(&tv, 0); - return tv.tv_sec * 1000 + tv.tv_usec / 1000; -#elif PLATFORM(QT) - QDateTime t = QDateTime::currentDateTime(); - return t.toTime_t() * 1000 + t.time().msec(); #elif PLATFORM(WIN_OS) union { FILETIME fileTime; @@ -97,7 +81,8 @@ static inline unsigned getCPUTime() return userTime.fileTimeAsLong / 10000 + kernelTime.fileTimeAsLong / 10000; #else -#error Platform does not have getCurrentTime function + // FIXME: We should return the time the current thread has spent executing. + return currentTime() * 1000; #endif } diff --git a/JavaScriptCore/runtime/UString.cpp b/JavaScriptCore/runtime/UString.cpp index 118751e..50d23c4 100644 --- a/JavaScriptCore/runtime/UString.cpp +++ b/JavaScriptCore/runtime/UString.cpp @@ -30,20 +30,20 @@ #include "Identifier.h" #include "Operations.h" #include <ctype.h> -#include <float.h> #include <limits.h> +#include <limits> #include <math.h> #include <stdio.h> #include <stdlib.h> +#include <string.h> #include <wtf/ASCIICType.h> #include <wtf/Assertions.h> #include <wtf/MathExtras.h> +#include <wtf/StringExtras.h> #include <wtf/Vector.h> #include <wtf/unicode/UTF8.h> +#include <wtf/StringExtras.h> -#if HAVE(STRING_H) -#include <string.h> -#endif #if HAVE(STRINGS_H) #include <strings.h> #endif @@ -68,20 +68,20 @@ static const int minLengthToShare = 10; static inline size_t overflowIndicator() { return std::numeric_limits<size_t>::max(); } static inline size_t maxUChars() { return std::numeric_limits<size_t>::max() / sizeof(UChar); } -static inline UChar* allocChars(size_t length) +static inline PossiblyNull<UChar*> allocChars(size_t length) { ASSERT(length); if (length > maxUChars()) return 0; - return static_cast<UChar*>(tryFastMalloc(sizeof(UChar) * length)); + return tryFastMalloc(sizeof(UChar) * length); } -static inline UChar* reallocChars(UChar* buffer, size_t length) +static inline PossiblyNull<UChar*> reallocChars(UChar* buffer, size_t length) { ASSERT(length); if (length > maxUChars()) return 0; - return static_cast<UChar*>(tryFastRealloc(buffer, sizeof(UChar) * length)); + return tryFastRealloc(buffer, sizeof(UChar) * length); } static inline void copyChars(UChar* destination, const UChar* source, unsigned numCharacters) @@ -480,8 +480,7 @@ static inline bool expandCapacity(UString::Rep* rep, int requiredLength) if (requiredLength > base->capacity) { size_t newCapacity = expandedSize(requiredLength, base->preCapacity); UChar* oldBuf = base->buf; - base->buf = reallocChars(base->buf, newCapacity); - if (!base->buf) { + if (!reallocChars(base->buf, newCapacity).getValue(base->buf)) { base->buf = oldBuf; return false; } @@ -512,8 +511,7 @@ bool UString::Rep::reserveCapacity(int capacity) size_t newCapacity = expandedSize(capacity, base->preCapacity); UChar* oldBuf = base->buf; - base->buf = reallocChars(base->buf, newCapacity); - if (!base->buf) { + if (!reallocChars(base->buf, newCapacity).getValue(base->buf)) { base->buf = oldBuf; return false; } @@ -540,8 +538,8 @@ void UString::expandPreCapacity(int requiredPreCap) size_t newCapacity = expandedSize(requiredPreCap, base->capacity); int delta = newCapacity - base->capacity - base->preCapacity; - UChar* newBuf = allocChars(newCapacity); - if (!newBuf) { + UChar* newBuf; + if (!allocChars(newCapacity).getValue(newBuf)) { makeNull(); return; } @@ -566,8 +564,8 @@ static PassRefPtr<UString::Rep> createRep(const char* c) return &UString::Rep::empty(); size_t length = strlen(c); - UChar* d = allocChars(length); - if (!d) + UChar* d; + if (!allocChars(length).getValue(d)) return &UString::Rep::null(); else { for (size_t i = 0; i < length; i++) @@ -577,11 +575,33 @@ static PassRefPtr<UString::Rep> createRep(const char* c) } +static inline PassRefPtr<UString::Rep> createRep(const char* c, int length) +{ + if (!c) + return &UString::Rep::null(); + + if (!length) + return &UString::Rep::empty(); + + UChar* d; + if (!allocChars(length).getValue(d)) + return &UString::Rep::null(); + + for (int 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, length); +} + UString::UString(const char* c) : m_rep(createRep(c)) { } +UString::UString(const char* c, int length) + : m_rep(createRep(c, length)) +{ +} + UString::UString(const UChar* c, int length) { if (length == 0) @@ -656,8 +676,8 @@ static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Re } else { // This is shared in some way that prevents us from modifying base, so we must make a whole new string. size_t newCapacity = expandedSize(length, 0); - UChar* d = allocChars(newCapacity); - if (!d) + UChar* d; + if (!allocChars(newCapacity).getValue(d)) rep = &UString::Rep::null(); else { copyChars(d, rep->data(), thisSize); @@ -712,8 +732,8 @@ static ALWAYS_INLINE PassRefPtr<UString::Rep> concatenate(PassRefPtr<UString::Re } else { // This is shared in some way that prevents us from modifying base, so we must make a whole new string. size_t newCapacity = expandedSize(length, 0); - UChar* d = allocChars(newCapacity); - if (!d) + UChar* d; + if (!allocChars(newCapacity).getValue(d)) rep = &UString::Rep::null(); else { copyChars(d, rep->data(), thisSize); @@ -800,8 +820,8 @@ PassRefPtr<UString::Rep> concatenate(UString::Rep* a, UString::Rep* b) // 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) + UChar* d; + if (!allocChars(newCapacity).getValue(d)) return 0; copyChars(d, a->data(), aSize); copyChars(d + aSize, b->data(), bSize); @@ -942,6 +962,39 @@ UString UString::from(int i) return UString(p, static_cast<int>(end - p)); } +UString UString::from(long long 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 == std::numeric_limits<long long>::min()) { + char minBuf[1 + sizeof(i) * 3]; +#if PLATFORM(WIN_OS) + snprintf(minBuf, sizeof(minBuf) - 1, "%I64d", std::numeric_limits<long long>::min()); +#else + snprintf(minBuf, sizeof(minBuf) - 1, "%lld", std::numeric_limits<long long>::min()); +#endif + return UString(minBuf); + } else { + bool negative = false; + if (i < 0) { + negative = true; + i = -i; + } + while (i) { + *--p = static_cast<unsigned short>((i % 10) + '0'); + i /= 10; + } + if (negative) + *--p = '-'; + } + + return UString(p, static_cast<int>(end - p)); +} + UString UString::from(unsigned int u) { UChar buf[sizeof(u) * 3]; @@ -991,67 +1044,10 @@ UString UString::from(long l) UString UString::from(double d) { - // avoid ever printing -NaN, in JS conceptually there is only one NaN value - if (isnan(d)) - return "NaN"; - - char buf[80]; - int decimalPoint; - int sign; - - char result[80]; - WTF::dtoa(result, d, 0, &decimalPoint, &sign, NULL); - int length = static_cast<int>(strlen(result)); - - int i = 0; - if (sign) - buf[i++] = '-'; - - if (decimalPoint <= 0 && decimalPoint > -6) { - buf[i++] = '0'; - buf[i++] = '.'; - for (int j = decimalPoint; j < 0; j++) - buf[i++] = '0'; - strcpy(buf + i, result); - } else if (decimalPoint <= 21 && decimalPoint > 0) { - if (length <= decimalPoint) { - strcpy(buf + i, result); - i += length; - for (int j = 0; j < decimalPoint - length; j++) - buf[i++] = '0'; - buf[i] = '\0'; - } else { - strncpy(buf + i, result, decimalPoint); - i += decimalPoint; - buf[i++] = '.'; - strcpy(buf + i, result + decimalPoint); - } - } else if (result[0] < '0' || result[0] > '9') - strcpy(buf + i, result); - else { - buf[i++] = result[0]; - if (length > 1) { - buf[i++] = '.'; - strcpy(buf + i, result + 1); - i += length - 1; - } - - buf[i++] = 'e'; - buf[i++] = (decimalPoint >= 0) ? '+' : '-'; - // decimalPoint can't be more than 3 digits decimal given the - // nature of float representation - int exponential = decimalPoint - 1; - if (exponential < 0) - exponential = -exponential; - if (exponential >= 100) - buf[i++] = static_cast<char>('0' + exponential / 100); - if (exponential >= 10) - buf[i++] = static_cast<char>('0' + (exponential % 100) / 10); - buf[i++] = static_cast<char>('0' + exponential % 10); - buf[i++] = '\0'; - } - - return UString(buf); + DtoaBuffer buffer; + unsigned length; + doubleToStringInJavaScriptFormat(d, buffer, &length); + return UString(buffer, length); } UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, int rangeCount, const UString* separators, int separatorCount) const @@ -1076,8 +1072,8 @@ UString UString::spliceSubstringsWithSeparators(const Range* substringRanges, in if (totalLength == 0) return ""; - UChar* buffer = allocChars(totalLength); - if (!buffer) + UChar* buffer; + if (!allocChars(totalLength).getValue(buffer)) return null(); int maxCount = max(rangeCount, separatorCount); @@ -1105,8 +1101,8 @@ UString UString::replaceRange(int rangeStart, int rangeLength, const UString& re if (totalLength == 0) return ""; - UChar* buffer = allocChars(totalLength); - if (!buffer) + UChar* buffer; + if (!allocChars(totalLength).getValue(buffer)) return null(); copyChars(buffer, data(), rangeStart); @@ -1153,8 +1149,8 @@ UString& UString::append(const UString &t) } else { // This is shared in some way that prevents us from modifying base, so we must make a whole new string. size_t newCapacity = expandedSize(length, 0); - UChar* d = allocChars(newCapacity); - if (!d) + UChar* d; + if (!allocChars(newCapacity).getValue(d)) makeNull(); else { copyChars(d, data(), thisSize); @@ -1176,18 +1172,6 @@ UString& UString::append(const UChar* tData, int tSize) return *this; } -UString& UString::appendNumeric(int i) -{ - m_rep = concatenate(rep(), i); - return *this; -} - -UString& UString::appendNumeric(double d) -{ - m_rep = concatenate(rep(), d); - return *this; -} - UString& UString::append(const char* t) { m_rep = concatenate(m_rep.release(), t); @@ -1206,8 +1190,8 @@ UString& UString::append(UChar c) 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) + UChar* d; + if (!allocChars(newCapacity).getValue(d)) makeNull(); else { d[0] = c; @@ -1234,8 +1218,8 @@ UString& UString::append(UChar c) } else { // This is shared in some way that prevents us from modifying base, so we must make a whole new string. size_t newCapacity = expandedSize(length + 1, 0); - UChar* d = allocChars(newCapacity); - if (!d) + UChar* d; + if (!allocChars(newCapacity).getValue(d)) makeNull(); else { copyChars(d, data(), length); @@ -1313,8 +1297,7 @@ UString& UString::operator=(const char* c) m_rep->_hash = 0; m_rep->len = l; } else { - d = allocChars(l); - if (!d) { + if (!allocChars(l).getValue(d)) { makeNull(); return *this; } diff --git a/JavaScriptCore/runtime/UString.h b/JavaScriptCore/runtime/UString.h index d01b75d..9b046f2 100644 --- a/JavaScriptCore/runtime/UString.h +++ b/JavaScriptCore/runtime/UString.h @@ -91,7 +91,8 @@ namespace JSC { { // Guard against integer overflow if (size < (std::numeric_limits<size_t>::max() / sizeof(UChar))) { - if (void * buf = tryFastMalloc(size * sizeof(UChar))) + void* buf = 0; + if (tryFastMalloc(size * sizeof(UChar)).getValue(buf)) return adoptRef(new BaseString(static_cast<UChar*>(buf), 0, size)); } return adoptRef(new BaseString(0, 0, 0)); @@ -234,7 +235,10 @@ namespace JSC { public: UString(); + // Constructor for null-terminated ASCII string. UString(const char*); + // Constructor for non-null-terminated ASCII string. + UString(const char*, int length); UString(const UChar*, int length); UString(UChar*, int length, bool copy); @@ -256,6 +260,7 @@ namespace JSC { } static UString from(int); + static UString from(long long); static UString from(unsigned int); static UString from(long); static UString from(double); @@ -285,8 +290,6 @@ namespace JSC { UString& append(UChar); UString& append(char c) { return append(static_cast<UChar>(static_cast<unsigned char>(c))); } UString& append(const UChar*, int size); - UString& appendNumeric(int); - UString& appendNumeric(double); bool getCString(CStringBuffer&) const; diff --git a/JavaScriptCore/runtime/WeakRandom.h b/JavaScriptCore/runtime/WeakRandom.h new file mode 100644 index 0000000..ff3995e --- /dev/null +++ b/JavaScriptCore/runtime/WeakRandom.h @@ -0,0 +1,86 @@ +/* + * Copyright (C) 2009 Apple Inc. All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + * + * + * Copyright (c) 2009 Ian C. Bullard + * + * Permission is hereby granted, free of charge, to any person + * obtaining a copy of this software and associated documentation + * files (the "Software"), to deal in the Software without + * restriction, including without limitation the rights to use, + * copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following + * conditions: + * + * The above copyright notice and this permission notice shall be + * included in all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, + * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES + * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND + * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT + * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, + * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR + * OTHER DEALINGS IN THE SOFTWARE. + */ + +#ifndef WeakRandom_h +#define WeakRandom_h + +#include <limits.h> +#include <wtf/StdLibExtras.h> + +namespace JSC { + +class WeakRandom { +public: + WeakRandom(unsigned seed) + : m_low(seed ^ 0x49616E42) + , m_high(seed) + { + } + + double get() + { + return advance() / (UINT_MAX + 1.0); + } + +private: + unsigned advance() + { + m_high = (m_high << 16) + (m_high >> 16); + m_high += m_low; + m_low += m_high; + return m_high; + } + + unsigned m_low; + unsigned m_high; +}; + +} // namespace JSC + +#endif // WeakRandom_h diff --git a/JavaScriptCore/wrec/WRECGenerator.cpp b/JavaScriptCore/wrec/WRECGenerator.cpp index e2e8aba..e62add3 100644 --- a/JavaScriptCore/wrec/WRECGenerator.cpp +++ b/JavaScriptCore/wrec/WRECGenerator.cpp @@ -42,8 +42,8 @@ void Generator::generateEnter() { #if PLATFORM(X86) // On x86 edi & esi are callee preserved registers. - push(X86::edi); - push(X86::esi); + push(X86Registers::edi); + push(X86Registers::esi); #if COMPILER(MSVC) // Move the arguments into registers. @@ -72,8 +72,8 @@ void Generator::generateReturnSuccess() // Restore callee save registers. #if PLATFORM(X86) - pop(X86::esi); - pop(X86::edi); + pop(X86Registers::esi); + pop(X86Registers::edi); #endif ret(); } @@ -111,8 +111,8 @@ void Generator::generateReturnFailure() move(Imm32(-1), returnRegister); #if PLATFORM(X86) - pop(X86::esi); - pop(X86::edi); + pop(X86Registers::esi); + pop(X86Registers::edi); #endif ret(); } diff --git a/JavaScriptCore/wrec/WRECGenerator.h b/JavaScriptCore/wrec/WRECGenerator.h index 8562cac..294c3d0 100644 --- a/JavaScriptCore/wrec/WRECGenerator.h +++ b/JavaScriptCore/wrec/WRECGenerator.h @@ -63,26 +63,26 @@ namespace JSC { } #if PLATFORM(X86) - static const RegisterID input = X86::eax; - static const RegisterID index = X86::edx; - static const RegisterID length = X86::ecx; - static const RegisterID output = X86::edi; + static const RegisterID input = X86Registers::eax; + static const RegisterID index = X86Registers::edx; + static const RegisterID length = X86Registers::ecx; + static const RegisterID output = X86Registers::edi; - static const RegisterID character = X86::esi; - static const RegisterID repeatCount = X86::ebx; // How many times the current atom repeats in the current match. + static const RegisterID character = X86Registers::esi; + static const RegisterID repeatCount = X86Registers::ebx; // How many times the current atom repeats in the current match. - static const RegisterID returnRegister = X86::eax; + static const RegisterID returnRegister = X86Registers::eax; #endif #if PLATFORM(X86_64) - static const RegisterID input = X86::edi; - static const RegisterID index = X86::esi; - static const RegisterID length = X86::edx; - static const RegisterID output = X86::ecx; + static const RegisterID input = X86Registers::edi; + static const RegisterID index = X86Registers::esi; + static const RegisterID length = X86Registers::edx; + static const RegisterID output = X86Registers::ecx; - static const RegisterID character = X86::eax; - static const RegisterID repeatCount = X86::ebx; // How many times the current atom repeats in the current match. + static const RegisterID character = X86Registers::eax; + static const RegisterID repeatCount = X86Registers::ebx; // How many times the current atom repeats in the current match. - static const RegisterID returnRegister = X86::eax; + static const RegisterID returnRegister = X86Registers::eax; #endif void generateEnter(); diff --git a/JavaScriptCore/wscript b/JavaScriptCore/wscript index df11430..356950f 100644 --- a/JavaScriptCore/wscript +++ b/JavaScriptCore/wscript @@ -29,16 +29,16 @@ import commands from settings import * -jscore_excludes = ['jsc.cpp', 'ucptable.cpp', 'GOwnPtr.cpp'] -jscore_excludes.extend(get_excludes(jscore_dir, ['*CF.cpp'])) +jscore_excludes = ['jsc.cpp', 'ucptable.cpp'] +jscore_excludes.extend(get_excludes(jscore_dir, ['*CF.cpp', '*Symbian.cpp'])) sources = [] jscore_excludes.extend(get_excludes(jscore_dir, ['*Win.cpp', '*None.cpp'])) if building_on_win32: - jscore_excludes.append('ExecutableAllocatorPosix.cpp') - sources.append('jit/ExecutableAllocatorWin.cpp') + jscore_excludes += ['ExecutableAllocatorPosix.cpp', 'MarkStackPosix.cpp'] + sources += ['jit/ExecutableAllocatorWin.cpp', 'runtime/MarkStackWin.cpp'] else: jscore_excludes.append('JSStringRefBSTR.cpp') @@ -62,17 +62,14 @@ def set_options(opt): common_set_options(opt) def configure(conf): - common_configure(conf) + common_configure(conf) + generate_jscore_derived_sources() def build(bld): import Options - generate_jscore_derived_sources() - full_dirs = get_dirs_for_features(jscore_dir, features=[build_port], dirs=jscore_dirs) - print 'full_dirs = %r' % full_dirs - includes = common_includes + full_dirs # 1. A simple program @@ -81,7 +78,7 @@ def build(bld): includes = '. .. assembler wrec DerivedSources ForwardingHeaders ' + ' '.join(includes), source = sources, target = 'jscore', - uselib = 'WX ICU ' + waf_configname, + uselib = 'WX ICU ' + get_config(), uselib_local = '', install_path = output_dir) @@ -92,15 +89,15 @@ def build(bld): includes = '. .. assembler wrec DerivedSources ForwardingHeaders ' + ' '.join(includes), source = 'jsc.cpp', target = 'jsc', - uselib = 'WX ICU ' + waf_configname, + uselib = 'WX ICU ' + get_config(), uselib_local = 'jscore', install_path = output_dir, ) # we'll get an error if exceptions are on because of an unwind error when using __try if building_on_win32: - flags = obj.env.CPPFLAGS + flags = obj.env.CXXFLAGS flags.remove('/EHsc') - obj.env.CPPFLAGS = flags + obj.env.CXXFLAGS = flags bld.install_files(os.path.join(output_dir, 'JavaScriptCore'), 'API/*.h') diff --git a/JavaScriptCore/wtf/Assertions.cpp b/JavaScriptCore/wtf/Assertions.cpp index 819ed9a..6c5e2e3 100644 --- a/JavaScriptCore/wtf/Assertions.cpp +++ b/JavaScriptCore/wtf/Assertions.cpp @@ -105,7 +105,11 @@ static void vprintf_stderr_common(const char* format, va_list args) } while (size > 1024); } #endif +#if PLATFORM(SYMBIAN) + vfprintf(stdout, format, args); +#else vfprintf(stderr, format, args); +#endif } WTF_ATTRIBUTE_PRINTF(1, 2) diff --git a/JavaScriptCore/wtf/Assertions.h b/JavaScriptCore/wtf/Assertions.h index 59efd84..e3340f1 100644 --- a/JavaScriptCore/wtf/Assertions.h +++ b/JavaScriptCore/wtf/Assertions.h @@ -50,6 +50,11 @@ #include <inttypes.h> #endif +#if PLATFORM(SYMBIAN) +#include <e32def.h> +#include <e32debug.h> +#endif + #ifdef NDEBUG #define ASSERTIONS_DISABLED_DEFAULT 1 #else @@ -120,11 +125,18 @@ void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChann /* CRASH -- gets us into the debugger or the crash reporter -- signals are ignored by the crash reporter so we must do better */ #ifndef CRASH +#if PLATFORM(SYMBIAN) +#define CRASH() do { \ + __DEBUGGER(); \ + User::Panic(_L("Webkit CRASH"),0); \ + } while(false) +#else #define CRASH() do { \ *(int *)(uintptr_t)0xbbadbeef = 0; \ ((void(*)())0)(); /* More reliable, but doesn't say BBADBEEF */ \ } while(false) #endif +#endif /* ASSERT, ASSERT_WITH_MESSAGE, ASSERT_NOT_REACHED */ @@ -144,7 +156,11 @@ void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChann #if ASSERT_DISABLED #define ASSERT(assertion) ((void)0) +#if COMPILER(MSVC7) || COMPILER(WINSCW) +#define ASSERT_WITH_MESSAGE(assertion) ((void)0) +#else #define ASSERT_WITH_MESSAGE(assertion, ...) ((void)0) +#endif /* COMPILER(MSVC7) */ #define ASSERT_NOT_REACHED() ((void)0) #define ASSERT_UNUSED(variable, assertion) ((void)variable) @@ -156,7 +172,7 @@ void WTFLogVerbose(const char* file, int line, const char* function, WTFLogChann CRASH(); \ } \ while (0) -#if COMPILER(MSVC7) +#if COMPILER(MSVC7) || COMPILER(WINSCW) #define ASSERT_WITH_MESSAGE(assertion) ((void)0) #else #define ASSERT_WITH_MESSAGE(assertion, ...) do \ @@ -199,7 +215,7 @@ while (0) /* FATAL */ -#if FATAL_DISABLED +#if FATAL_DISABLED && !COMPILER(MSVC7) && !COMPILER(WINSCW) #define FATAL(...) ((void)0) #elif COMPILER(MSVC7) #define FATAL() ((void)0) @@ -212,9 +228,9 @@ while (0) /* LOG_ERROR */ -#if ERROR_DISABLED +#if ERROR_DISABLED && !COMPILER(MSVC7) && !COMPILER(WINSCW) #define LOG_ERROR(...) ((void)0) -#elif COMPILER(MSVC7) +#elif COMPILER(MSVC7) || COMPILER(WINSCW) #define LOG_ERROR() ((void)0) #else #define LOG_ERROR(...) WTFReportError(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, __VA_ARGS__) @@ -222,9 +238,9 @@ while (0) /* LOG */ -#if LOG_DISABLED +#if LOG_DISABLED && !COMPILER(MSVC7) && !COMPILER(WINSCW) #define LOG(channel, ...) ((void)0) -#elif COMPILER(MSVC7) +#elif COMPILER(MSVC7) || COMPILER(WINSCW) #define LOG() ((void)0) #else #define LOG(channel, ...) WTFLog(&JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__) @@ -234,9 +250,9 @@ while (0) /* LOG_VERBOSE */ -#if LOG_DISABLED +#if LOG_DISABLED && !COMPILER(MSVC7) && !COMPILER(WINSCW) #define LOG_VERBOSE(channel, ...) ((void)0) -#elif COMPILER(MSVC7) +#elif COMPILER(MSVC7) || COMPILER(WINSCW) #define LOG_VERBOSE(channel) ((void)0) #else #define LOG_VERBOSE(channel, ...) WTFLogVerbose(__FILE__, __LINE__, WTF_PRETTY_FUNCTION, &JOIN_LOG_CHANNEL_WITH_PREFIX(LOG_CHANNEL_PREFIX, channel), __VA_ARGS__) diff --git a/JavaScriptCore/wtf/ByteArray.h b/JavaScriptCore/wtf/ByteArray.h index 96e9cc2..f5f5ded 100644 --- a/JavaScriptCore/wtf/ByteArray.h +++ b/JavaScriptCore/wtf/ByteArray.h @@ -45,6 +45,13 @@ namespace WTF { m_data[index] = static_cast<unsigned char>(value + 0.5); } + void set(unsigned index, unsigned char value) + { + if (index >= m_size) + return; + m_data[index] = value; + } + bool get(unsigned index, unsigned char& result) const { if (index >= m_size) @@ -53,6 +60,12 @@ namespace WTF { return true; } + unsigned char get(unsigned index) const + { + ASSERT(index < m_size); + return m_data[index]; + } + unsigned char* data() { return m_data; } void deref() diff --git a/JavaScriptCore/wtf/CrossThreadRefCounted.h b/JavaScriptCore/wtf/CrossThreadRefCounted.h index 6a05211..f682f0d 100644 --- a/JavaScriptCore/wtf/CrossThreadRefCounted.h +++ b/JavaScriptCore/wtf/CrossThreadRefCounted.h @@ -70,10 +70,6 @@ namespace WTF { return !m_refCounter.hasOneRef() || (m_threadSafeRefCounter && !m_threadSafeRefCounter->hasOneRef()); } -#ifndef NDEBUG - bool mayBePassedToAnotherThread() const { ASSERT(!m_threadId); return m_refCounter.hasOneRef(); } -#endif - private: CrossThreadRefCounted(T* data, ThreadSafeSharedBase* threadedCounter) : m_threadSafeRefCounter(threadedCounter) @@ -92,6 +88,10 @@ namespace WTF { void threadSafeDeref(); +#ifndef NDEBUG + bool isOwnedByCurrentThread() const { return !m_threadId || m_threadId == currentThread(); } +#endif + RefCountedBase m_refCounter; ThreadSafeSharedBase* m_threadSafeRefCounter; T* m_data; @@ -103,7 +103,7 @@ namespace WTF { template<class T> void CrossThreadRefCounted<T>::ref() { - ASSERT(!m_threadId || m_threadId == currentThread()); + ASSERT(isOwnedByCurrentThread()); m_refCounter.ref(); #ifndef NDEBUG // Store the threadId as soon as the ref count gets to 2. @@ -119,7 +119,7 @@ namespace WTF { template<class T> void CrossThreadRefCounted<T>::deref() { - ASSERT(!m_threadId || m_threadId == currentThread()); + ASSERT(isOwnedByCurrentThread()); if (m_refCounter.derefBase()) { threadSafeDeref(); delete this; @@ -146,10 +146,12 @@ namespace WTF { template<class T> PassRefPtr<CrossThreadRefCounted<T> > CrossThreadRefCounted<T>::crossThreadCopy() { + ASSERT(isOwnedByCurrentThread()); if (m_threadSafeRefCounter) m_threadSafeRefCounter->ref(); else m_threadSafeRefCounter = new ThreadSafeSharedBase(2); + return adoptRef(new CrossThreadRefCounted<T>(m_data, m_threadSafeRefCounter)); } diff --git a/JavaScriptCore/wtf/CurrentTime.cpp b/JavaScriptCore/wtf/CurrentTime.cpp index 45c724a..b36cae5 100644 --- a/JavaScriptCore/wtf/CurrentTime.cpp +++ b/JavaScriptCore/wtf/CurrentTime.cpp @@ -63,6 +63,10 @@ extern "C" time_t mktime(struct tm *t); #include <sys/time.h> #endif +#if PLATFORM(CHROMIUM) +#error Chromium uses a different timer implementation +#endif + namespace WTF { const double msPerSecond = 1000.0; @@ -286,24 +290,4 @@ double currentTime() #endif -#if PLATFORM(ANDROID) - -uint32_t get_thread_msec() -{ -#if defined(HAVE_POSIX_CLOCKS) - struct timespec tm; - - clock_gettime(CLOCK_THREAD_CPUTIME_ID, &tm); - return tm.tv_sec * 1000LL + tm.tv_nsec / 1000000; -#else - struct timeval now; - struct timezone zone; - - gettimeofday(&now, &zone); - return now.tv_sec * 1000LL + now.tv_usec / 1000; -#endif -} - -#endif - } // namespace WTF diff --git a/JavaScriptCore/wtf/CurrentTime.h b/JavaScriptCore/wtf/CurrentTime.h index 436e054..472770e 100644 --- a/JavaScriptCore/wtf/CurrentTime.h +++ b/JavaScriptCore/wtf/CurrentTime.h @@ -32,16 +32,31 @@ #ifndef CurrentTime_h #define CurrentTime_h +#include <time.h> + namespace WTF { - // Returns the current system (UTC) time in seconds, starting January 1, 1970. - // Precision varies depending on a platform but usually is as good or better + // Returns the current UTC time in seconds, counted from January 1, 1970. + // Precision varies depending on platform but is usually as good or better // than a millisecond. double currentTime(); -#if PLATFORM(ANDROID) - uint32_t get_thread_msec(); -#endif + // Same thing, in milliseconds. + inline double currentTimeMS() + { + return currentTime() * 1000.0; + } + + inline void getLocalTime(const time_t* localTime, struct tm* localTM) + { + #if COMPILER(MSVC7) || COMPILER(MINGW) || PLATFORM(WINCE) + *localTM = *localtime(localTime); + #elif COMPILER(MSVC) + localtime_s(localTM, localTime); + #else + localtime_r(localTime, localTM); + #endif + } } // namespace WTF diff --git a/JavaScriptCore/wtf/DateMath.cpp b/JavaScriptCore/wtf/DateMath.cpp index 6a5b22f..187fa63 100644 --- a/JavaScriptCore/wtf/DateMath.cpp +++ b/JavaScriptCore/wtf/DateMath.cpp @@ -39,6 +39,33 @@ * other provisions required by the MPL or the GPL, as the case may be. * If you do not delete the provisions above, a recipient may use your * version of this file under any of the LGPL, the MPL or the GPL. + + * Copyright 2006-2008 the V8 project authors. All rights reserved. + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are + * met: + * + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above + * copyright notice, this list of conditions and the following + * disclaimer in the documentation and/or other materials provided + * with the distribution. + * * Neither the name of Google Inc. nor the names of its + * contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR + * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -61,11 +88,7 @@ #include <errno.h> #endif -#if PLATFORM(DARWIN) -#include <notify.h> -#endif - -#if PLATFORM(WINCE) && !PLATFORM(QT) +#if PLATFORM(WINCE) extern "C" size_t strftime(char * const s, const size_t maxsize, const char * const format, const struct tm * const t); extern "C" struct tm * localtime(const time_t *timer); #endif @@ -78,8 +101,14 @@ extern "C" struct tm * localtime(const time_t *timer); #include <sys/timeb.h> #endif +#if USE(JSC) +#include "CallFrame.h" +#endif + #define NaN std::numeric_limits<double>::quiet_NaN() +using namespace WTF; + namespace WTF { /* Constants */ @@ -293,28 +322,6 @@ static int dateToDayInYear(int year, int month, int day) return yearday + monthday + day - 1; } -double getCurrentUTCTime() -{ - return floor(getCurrentUTCTimeWithMicroseconds()); -} - -// Returns current time in milliseconds since 1 Jan 1970. -double getCurrentUTCTimeWithMicroseconds() -{ - return currentTime() * 1000.0; -} - -void getLocalTime(const time_t* localTime, struct tm* localTM) -{ -#if COMPILER(MSVC7) || COMPILER(MINGW) || PLATFORM(WINCE) - *localTM = *localtime(localTime); -#elif COMPILER(MSVC) - localtime_s(localTM, localTime); -#else - localtime_r(localTime, localTM); -#endif -} - // There is a hard limit at 2038 that we currently do not have a workaround // for (rdar://problem/5052975). static inline int maximumYearForDST() @@ -328,7 +335,7 @@ static inline int minimumYearForDST() // greater than the max year minus 27 (2010), we want to use the max year // minus 27 instead, to ensure there is a range of 28 years that all years // can map to. - return std::min(msToYear(getCurrentUTCTime()), maximumYearForDST() - 27) ; + return std::min(msToYear(jsCurrentTime()), maximumYearForDST() - 27) ; } /* @@ -399,44 +406,10 @@ static int32_t calculateUTCOffset() return static_cast<int32_t>(utcOffset * 1000); } -#if PLATFORM(DARWIN) -static int32_t s_cachedUTCOffset; // In milliseconds. An assumption here is that access to an int32_t variable is atomic on platforms that take this code path. -static bool s_haveCachedUTCOffset; -static int s_notificationToken; -#endif - -/* - * Get the difference in milliseconds between this time zone and UTC (GMT) - * NOT including DST. - */ -double getUTCOffset() -{ -#if PLATFORM(DARWIN) - if (s_haveCachedUTCOffset) { - int notified; - uint32_t status = notify_check(s_notificationToken, ¬ified); - if (status == NOTIFY_STATUS_OK && !notified) - return s_cachedUTCOffset; - } -#endif - - int32_t utcOffset = calculateUTCOffset(); - -#if PLATFORM(DARWIN) - // Theoretically, it is possible that several threads will be executing this code at once, in which case we will have a race condition, - // and a newer value may be overwritten. In practice, time zones don't change that often. - s_cachedUTCOffset = utcOffset; -#endif - - return utcOffset; -} - /* - * Get the DST offset for the time passed in. Takes - * seconds (not milliseconds) and cannot handle dates before 1970 - * on some OS' + * Get the DST offset for the time passed in. */ -static double getDSTOffsetSimple(double localTimeSeconds, double utcOffset) +static double calculateDSTOffsetSimple(double localTimeSeconds, double utcOffset) { if (localTimeSeconds > maxUnixTime) localTimeSeconds = maxUnixTime; @@ -465,9 +438,9 @@ static double getDSTOffsetSimple(double localTimeSeconds, double utcOffset) } // Get the DST offset, given a time in UTC -static double getDSTOffset(double ms, double utcOffset) +static double calculateDSTOffset(double ms, double utcOffset) { - // On Mac OS X, the call to localtime (see getDSTOffsetSimple) will return historically accurate + // On Mac OS X, the call to localtime (see calculateDSTOffsetSimple) 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 @@ -483,66 +456,18 @@ static double getDSTOffset(double ms, double utcOffset) 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 = outputIsUTC ? 0 : static_cast<long>((dstOff + utcOff) / msPerSecond); - tm.timeZone = NULL; + return calculateDSTOffsetSimple(ms / msPerSecond, utcOffset); } void initializeDates() { #ifndef NDEBUG static bool alreadyInitialized; - ASSERT(!alreadyInitialized++); + ASSERT(!alreadyInitialized); + alreadyInitialized = true; #endif equivalentYearForDST(2000); // Need to call once to initialize a static used in this function. -#if PLATFORM(DARWIN) - // Register for a notification whenever the time zone changes. - uint32_t status = notify_register_check("com.apple.system.timezone", &s_notificationToken); - if (status == NOTIFY_STATUS_OK) { - s_cachedUTCOffset = calculateUTCOffset(); - s_haveCachedUTCOffset = true; - } -#endif } static inline double ymdhmsToSeconds(long year, int mon, int day, int hour, int minute, int second) @@ -623,8 +548,12 @@ static bool parseLong(const char* string, char** stopPosition, int base, long* r return true; } -double parseDateFromNullTerminatedCharacters(const char* dateString) +// Odd case where 'exec' is allowed to be 0, to accomodate a caller in WebCore. +static double parseDateFromNullTerminatedCharacters(const char* dateString, bool& haveTZ, int& offset) { + haveTZ = false; + offset = 0; + // This parses a date in the form: // Tuesday, 09-Nov-99 23:12:40 GMT // or @@ -825,9 +754,6 @@ double parseDateFromNullTerminatedCharacters(const char* 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) { @@ -890,23 +816,25 @@ double parseDateFromNullTerminatedCharacters(const char* dateString) else year += 1900; } + + return ymdhmsToSeconds(year, month + 1, day, hour, minute, second) * msPerSecond; +} + +double parseDateFromNullTerminatedCharacters(const char* dateString) +{ + bool haveTZ; + int offset; + double ms = parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset); + if (isnan(ms)) + return NaN; // fall back to local timezone if (!haveTZ) { - GregorianDateTime t; - t.monthDay = day; - t.month = month; - t.year = year - 1900; - t.isDST = -1; - t.second = second; - t.minute = minute; - t.hour = hour; - - // Use our gregorianDateTimeToMS() rather than mktime() as the latter can't handle the full year range. - return gregorianDateTimeToMS(t, 0, false); + double utcOffset = calculateUTCOffset(); + double dstOffset = calculateDSTOffset(ms, utcOffset); + offset = static_cast<int>((utcOffset + dstOffset) / msPerMinute); } - - return (ymdhmsToSeconds(year, month + 1, day, hour, minute, second) - (offset * 60.0)) * msPerSecond; + return ms - (offset * msPerMinute); } double timeClip(double t) @@ -917,6 +845,143 @@ double timeClip(double t) return NaN; return trunc(t); } +} // namespace WTF + +#if USE(JSC) +namespace JSC { + +// Get the DST offset for the time passed in. +// +// NOTE: The implementation relies on the fact that no time zones have +// more than one daylight savings offset change per month. +// If this function is called with NaN it returns NaN. +static double getDSTOffset(ExecState* exec, double ms, double utcOffset) +{ + DSTOffsetCache& cache = exec->globalData().dstOffsetCache; + double start = cache.start; + double end = cache.end; + + if (start <= ms) { + // If the time fits in the cached interval, return the cached offset. + if (ms <= end) return cache.offset; + + // Compute a possible new interval end. + double newEnd = end + cache.increment; + + if (ms <= newEnd) { + double endOffset = calculateDSTOffset(newEnd, utcOffset); + if (cache.offset == endOffset) { + // If the offset at the end of the new interval still matches + // the offset in the cache, we grow the cached time interval + // and return the offset. + cache.end = newEnd; + cache.increment = msPerMonth; + return endOffset; + } else { + double offset = calculateDSTOffset(ms, utcOffset); + if (offset == endOffset) { + // The offset at the given time is equal to the offset at the + // new end of the interval, so that means that we've just skipped + // the point in time where the DST offset change occurred. Updated + // the interval to reflect this and reset the increment. + cache.start = ms; + cache.end = newEnd; + cache.increment = msPerMonth; + } else { + // The interval contains a DST offset change and the given time is + // before it. Adjust the increment to avoid a linear search for + // the offset change point and change the end of the interval. + cache.increment /= 3; + cache.end = ms; + } + // Update the offset in the cache and return it. + cache.offset = offset; + return offset; + } + } + } + + // Compute the DST offset for the time and shrink the cache interval + // to only contain the time. This allows fast repeated DST offset + // computations for the same time. + double offset = calculateDSTOffset(ms, utcOffset); + cache.offset = offset; + cache.start = ms; + cache.end = ms; + cache.increment = msPerMonth; + return offset; +} + +/* + * Get the difference in milliseconds between this time zone and UTC (GMT) + * NOT including DST. + */ +double getUTCOffset(ExecState* exec) +{ + double utcOffset = exec->globalData().cachedUTCOffset; + if (!isnan(utcOffset)) + return utcOffset; + exec->globalData().cachedUTCOffset = calculateUTCOffset(); + return exec->globalData().cachedUTCOffset; +} +double gregorianDateTimeToMS(ExecState* exec, const GregorianDateTime& t, double milliSeconds, bool inputIsUTC) +{ + int day = dateToDayInYear(t.year + 1900, t.month, t.monthDay); + double ms = timeToMS(t.hour, t.minute, t.second, milliSeconds); + double result = (day * WTF::msPerDay) + ms; -} // namespace WTF + if (!inputIsUTC) { // convert to UTC + double utcOffset = getUTCOffset(exec); + result -= utcOffset; + result -= getDSTOffset(exec, result, utcOffset); + } + + return result; +} + +// input is UTC +void msToGregorianDateTime(ExecState* exec, double ms, bool outputIsUTC, GregorianDateTime& tm) +{ + double dstOff = 0.0; + double utcOff = 0.0; + if (!outputIsUTC) { + utcOff = getUTCOffset(exec); + dstOff = getDSTOffset(exec, ms, utcOff); + ms += dstOff + utcOff; + } + + const int year = msToYear(ms); + tm.second = msToSeconds(ms); + tm.minute = msToMinutes(ms); + tm.hour = msToHours(ms); + tm.weekDay = msToWeekDay(ms); + tm.yearDay = dayInYear(ms, year); + tm.monthDay = dayInMonthFromDayInYear(tm.yearDay, isLeapYear(year)); + tm.month = monthFromDayInYear(tm.yearDay, isLeapYear(year)); + tm.year = year - 1900; + tm.isDST = dstOff != 0.0; + tm.utcOffset = static_cast<long>((dstOff + utcOff) / WTF::msPerSecond); + tm.timeZone = NULL; +} + +double parseDateFromNullTerminatedCharacters(ExecState* exec, const char* dateString) +{ + ASSERT(exec); + bool haveTZ; + int offset; + double ms = WTF::parseDateFromNullTerminatedCharacters(dateString, haveTZ, offset); + if (isnan(ms)) + return NaN; + + // fall back to local timezone + if (!haveTZ) { + double utcOffset = getUTCOffset(exec); + double dstOffset = getDSTOffset(exec, ms, utcOffset); + offset = static_cast<int>((utcOffset + dstOffset) / WTF::msPerMinute); + } + return ms - (offset * WTF::msPerMinute); +} + +} // namespace JSC +#endif // USE(JSC) diff --git a/JavaScriptCore/wtf/DateMath.h b/JavaScriptCore/wtf/DateMath.h index 6110f76..6d4ac1e 100644 --- a/JavaScriptCore/wtf/DateMath.h +++ b/JavaScriptCore/wtf/DateMath.h @@ -42,27 +42,27 @@ #ifndef DateMath_h #define DateMath_h -#include <time.h> +#include <math.h> #include <string.h> +#include <time.h> +#include <wtf/CurrentTime.h> #include <wtf/Noncopyable.h> +#include <wtf/UnusedParam.h> namespace WTF { - -struct GregorianDateTime; - void initializeDates(); -void msToGregorianDateTime(double, bool outputIsUTC, GregorianDateTime&); -double gregorianDateTimeToMS(const GregorianDateTime&, double, bool inputIsUTC); -double getUTCOffset(); int equivalentYearForDST(int year); -double getCurrentUTCTime(); -double getCurrentUTCTimeWithMicroseconds(); -void getLocalTime(const time_t*, tm*); // Not really math related, but this is currently the only shared place to put these. -double parseDateFromNullTerminatedCharacters(const char*); +double parseDateFromNullTerminatedCharacters(const char* dateString); double timeClip(double); +inline double jsCurrentTime() +{ + // JavaScript doesn't recognize fractions of a millisecond. + return floor(WTF::currentTimeMS()); +} + 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" }; @@ -74,9 +74,22 @@ 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; +const double msPerMonth = 2592000000.0; -// Intentionally overridding the default tm of the system -// Tee members of tm differ on various operating systems. +} // namespace WTF + +#if USE(JSC) +namespace JSC { +class ExecState; +struct GregorianDateTime; + +void msToGregorianDateTime(ExecState*, double, bool outputIsUTC, GregorianDateTime&); +double gregorianDateTimeToMS(ExecState*, const GregorianDateTime&, double, bool inputIsUTC); +double getUTCOffset(ExecState*); +double parseDateFromNullTerminatedCharacters(ExecState*, const char* dateString); + +// Intentionally overridding the default tm of the system. +// The members of tm differ on various operating systems. struct GregorianDateTime : Noncopyable { GregorianDateTime() : second(0) @@ -98,7 +111,7 @@ struct GregorianDateTime : Noncopyable { delete [] timeZone; } - GregorianDateTime(const tm& inTm) + GregorianDateTime(ExecState* exec, const tm& inTm) : second(inTm.tm_sec) , minute(inTm.tm_min) , hour(inTm.tm_hour) @@ -109,10 +122,11 @@ struct GregorianDateTime : Noncopyable { , year(inTm.tm_year) , isDST(inTm.tm_isdst) { + UNUSED_PARAM(exec); #if HAVE(TM_GMTOFF) utcOffset = static_cast<int>(inTm.tm_gmtoff); #else - utcOffset = static_cast<int>(getUTCOffset() / msPerSecond + (isDST ? secondsPerHour : 0)); + utcOffset = static_cast<int>(getUTCOffset(exec) / WTF::msPerSecond + (isDST ? WTF::secondsPerHour : 0)); #endif #if HAVE(TM_ZONE) @@ -186,7 +200,7 @@ static inline int gmtoffset(const GregorianDateTime& t) { return t.utcOffset; } - -} // namespace WTF +} // namespace JSC +#endif // USE(JSC) #endif // DateMath_h diff --git a/JavaScriptCore/wtf/DisallowCType.h b/JavaScriptCore/wtf/DisallowCType.h index 5dccb0e..436f7f2 100644 --- a/JavaScriptCore/wtf/DisallowCType.h +++ b/JavaScriptCore/wtf/DisallowCType.h @@ -54,21 +54,21 @@ #undef tolower #undef toupper -#define isalnum WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define isalpha WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define isascii WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define isblank WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define iscntrl WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define isdigit WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define isgraph WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define islower WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define isprint WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define ispunct WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define isspace WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define isupper WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define isxdigit WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define toascii WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define tolower WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h -#define toupper WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isalnum isalnum_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isalpha isalpha_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isascii isascii_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isblank isblank_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define iscntrl iscntrl_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isdigit isdigit_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isgraph isgraph_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define islower islower_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isprint isprint_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define ispunct ispunct_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isspace isspace_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isupper isupper_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define isxdigit isxdigit_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define toascii toascii_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define tolower tolower_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h +#define toupper toupper_WTF_Please_use_ASCIICType_instead_of_ctype_see_comment_in_ASCIICType_h #endif diff --git a/JavaScriptCore/wtf/FastAllocBase.h b/JavaScriptCore/wtf/FastAllocBase.h index 9fcbbc1..81b1de0 100644 --- a/JavaScriptCore/wtf/FastAllocBase.h +++ b/JavaScriptCore/wtf/FastAllocBase.h @@ -301,6 +301,16 @@ namespace WTF { fastFree(p); } + template <typename T> + inline void fastDeleteSkippingDestructor(T* p) + { + if (!p) + return; + + fastMallocMatchValidateFree(p, Internal::AllocTypeFastNew); + fastFree(p); + } + namespace Internal { // This is a support template for fastDeleteArray. // This handles the case wherein T has a trivial dtor. @@ -397,7 +407,7 @@ namespace WTF { } // namespace WTF -// Using WTF::FastAllocBase to avoid using FastAllocBase's explicit qualification by WTF::. using WTF::FastAllocBase; +using WTF::fastDeleteSkippingDestructor; #endif // FastAllocBase_h diff --git a/JavaScriptCore/wtf/FastMalloc.cpp b/JavaScriptCore/wtf/FastMalloc.cpp index c14b755..6cd8ef0 100644 --- a/JavaScriptCore/wtf/FastMalloc.cpp +++ b/JavaScriptCore/wtf/FastMalloc.cpp @@ -178,10 +178,10 @@ void* fastZeroedMalloc(size_t n) return result; } -void* tryFastZeroedMalloc(size_t n) +TryMallocReturnValue tryFastZeroedMalloc(size_t n) { - void* result = tryFastMalloc(n); - if (!result) + void* result; + if (!tryFastMalloc(n).getValue(result)) return 0; memset(result, 0, n); return result; @@ -200,7 +200,7 @@ void* tryFastZeroedMalloc(size_t n) namespace WTF { -void* tryFastMalloc(size_t n) +TryMallocReturnValue tryFastMalloc(size_t n) { ASSERT(!isForbidden()); @@ -226,7 +226,9 @@ void* fastMalloc(size_t n) ASSERT(!isForbidden()); #if ENABLE(FAST_MALLOC_MATCH_VALIDATION) - void* result = tryFastMalloc(n); + TryMallocReturnValue returnValue = tryFastMalloc(n); + void* result; + returnValue.getValue(result); #else void* result = malloc(n); #endif @@ -236,7 +238,7 @@ void* fastMalloc(size_t n) return result; } -void* tryFastCalloc(size_t n_elements, size_t element_size) +TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size) { ASSERT(!isForbidden()); @@ -264,7 +266,9 @@ void* fastCalloc(size_t n_elements, size_t element_size) ASSERT(!isForbidden()); #if ENABLE(FAST_MALLOC_MATCH_VALIDATION) - void* result = tryFastCalloc(n_elements, element_size); + TryMallocReturnValue returnValue = tryFastCalloc(n_elements, element_size); + void* result; + returnValue.getValue(result); #else void* result = calloc(n_elements, element_size); #endif @@ -291,7 +295,7 @@ void fastFree(void* p) #endif } -void* tryFastRealloc(void* p, size_t n) +TryMallocReturnValue tryFastRealloc(void* p, size_t n) { ASSERT(!isForbidden()); @@ -323,7 +327,9 @@ void* fastRealloc(void* p, size_t n) ASSERT(!isForbidden()); #if ENABLE(FAST_MALLOC_MATCH_VALIDATION) - void* result = tryFastRealloc(p, n); + TryMallocReturnValue returnValue = tryFastRealloc(p, n); + void* result; + returnValue.getValue(result); #else void* result = realloc(p, n); #endif @@ -373,6 +379,9 @@ extern "C" const int jscore_fastmalloc_introspection = 0; #include <stdarg.h> #include <stddef.h> #include <stdio.h> +#if PLATFORM(UNIX) +#include <unistd.h> +#endif #if COMPILER(MSVC) #ifndef WIN32_LEAN_AND_MEAN #define WIN32_LEAN_AND_MEAN @@ -385,6 +394,7 @@ extern "C" const int jscore_fastmalloc_introspection = 0; #if PLATFORM(DARWIN) #include "MallocZoneSupport.h" #include <wtf/HashSet.h> +#include <wtf/Vector.h> #endif #ifndef PRIuS @@ -539,7 +549,7 @@ static const size_t kNumClasses = 68; static const size_t kPageMapBigAllocationThreshold = 128 << 20; // Minimum number of pages to fetch from system at a time. Must be -// significantly bigger than kBlockSize to amortize system-call +// significantly bigger than kPageSize to amortize system-call // overhead, and also to reduce external fragementation. Also, we // should keep this value big because various incarnations of Linux // have small limits on the number of mmap() regions per @@ -2268,7 +2278,7 @@ static inline TCMalloc_PageHeap* getPageHeap() #define pageheap getPageHeap() #if USE_BACKGROUND_THREAD_TO_SCAVENGE_MEMORY -#if PLATFORM(WIN) +#if PLATFORM(WIN_OS) static void sleep(unsigned seconds) { ::Sleep(seconds * 1000); @@ -2277,6 +2287,10 @@ static void sleep(unsigned seconds) void TCMalloc_PageHeap::scavengerThread() { +#if HAVE(PTHREAD_SETNAME_NP) + pthread_setname_np("JavaScriptCore: FastMalloc scavenger"); +#endif + while (1) { if (!shouldContinueScavenging()) { pthread_mutex_lock(&m_scavengeMutex); @@ -2382,7 +2396,7 @@ ALWAYS_INLINE void TCMalloc_Central_FreeList::ReleaseToSpans(void* object) { // The following check is expensive, so it is disabled by default if (false) { // Check that object does not occur in list - int got = 0; + unsigned got = 0; for (void* p = span->objects; p != NULL; p = *((void**) p)) { ASSERT(p != object); got++; @@ -3576,7 +3590,7 @@ void* fastMalloc(size_t size) return malloc<true>(size); } -void* tryFastMalloc(size_t size) +TryMallocReturnValue tryFastMalloc(size_t size) { return malloc<false>(size); } @@ -3637,7 +3651,7 @@ void* fastCalloc(size_t n, size_t elem_size) return calloc<true>(n, elem_size); } -void* tryFastCalloc(size_t n, size_t elem_size) +TryMallocReturnValue tryFastCalloc(size_t n, size_t elem_size) { return calloc<false>(n, elem_size); } @@ -3701,7 +3715,7 @@ void* fastRealloc(void* old_ptr, size_t new_size) return realloc<true>(old_ptr, new_size); } -void* tryFastRealloc(void* old_ptr, size_t new_size) +TryMallocReturnValue tryFastRealloc(void* old_ptr, size_t new_size) { return realloc<false>(old_ptr, new_size); } diff --git a/JavaScriptCore/wtf/FastMalloc.h b/JavaScriptCore/wtf/FastMalloc.h index 787251f..abe4a58 100644 --- a/JavaScriptCore/wtf/FastMalloc.h +++ b/JavaScriptCore/wtf/FastMalloc.h @@ -22,6 +22,7 @@ #define WTF_FastMalloc_h #include "Platform.h" +#include "PossiblyNull.h" #include <stdlib.h> #include <new> @@ -33,11 +34,42 @@ namespace WTF { void* fastCalloc(size_t numElements, size_t elementSize); void* fastRealloc(void*, size_t); - // These functions return 0 if an allocation fails. - void* tryFastMalloc(size_t); - void* tryFastZeroedMalloc(size_t); - void* tryFastCalloc(size_t numElements, size_t elementSize); - void* tryFastRealloc(void*, size_t); + struct TryMallocReturnValue { + TryMallocReturnValue(void* data) + : m_data(data) + { + } + TryMallocReturnValue(const TryMallocReturnValue& source) + : m_data(source.m_data) + { + source.m_data = 0; + } + ~TryMallocReturnValue() { ASSERT(!m_data); } + template <typename T> bool getValue(T& data) WARN_UNUSED_RETURN; + template <typename T> operator PossiblyNull<T>() + { + T value; + getValue(value); + return PossiblyNull<T>(value); + } + private: + mutable void* m_data; + }; + + template <typename T> bool TryMallocReturnValue::getValue(T& data) + { + union u { void* data; T target; } res; + res.data = m_data; + data = res.target; + bool returnValue = !!m_data; + m_data = 0; + return returnValue; + } + + TryMallocReturnValue tryFastMalloc(size_t n); + TryMallocReturnValue tryFastZeroedMalloc(size_t n); + TryMallocReturnValue tryFastCalloc(size_t n_elements, size_t element_size); + TryMallocReturnValue tryFastRealloc(void* p, size_t n); void fastFree(void*); @@ -181,14 +213,26 @@ using WTF::fastMallocAllow; // debug-only code to make sure we don't use the system malloc via the default operator // new by accident. -WTF_PRIVATE_INLINE void* operator new(size_t size) { return fastMalloc(size); } +// We musn't customize the global operator new and delete for the Qt port. +#if !PLATFORM(QT) + +#if COMPILER(MSVC) +#pragma warning(push) +#pragma warning(disable: 4290) // Disable the C++ exception specification ignored warning. +#endif +WTF_PRIVATE_INLINE void* operator new(size_t size) throw (std::bad_alloc) { return fastMalloc(size); } WTF_PRIVATE_INLINE void* operator new(size_t size, const std::nothrow_t&) throw() { return fastMalloc(size); } -WTF_PRIVATE_INLINE void operator delete(void* p) { fastFree(p); } +WTF_PRIVATE_INLINE void operator delete(void* p) throw() { fastFree(p); } WTF_PRIVATE_INLINE void operator delete(void* p, const std::nothrow_t&) throw() { fastFree(p); } -WTF_PRIVATE_INLINE void* operator new[](size_t size) { return fastMalloc(size); } +WTF_PRIVATE_INLINE void* operator new[](size_t size) throw (std::bad_alloc) { return fastMalloc(size); } WTF_PRIVATE_INLINE void* operator new[](size_t size, const std::nothrow_t&) throw() { return fastMalloc(size); } -WTF_PRIVATE_INLINE void operator delete[](void* p) { fastFree(p); } +WTF_PRIVATE_INLINE void operator delete[](void* p) throw() { fastFree(p); } WTF_PRIVATE_INLINE void operator delete[](void* p, const std::nothrow_t&) throw() { fastFree(p); } +#if COMPILER(MSVC) +#pragma warning(pop) +#endif + +#endif #endif diff --git a/JavaScriptCore/wtf/Forward.h b/JavaScriptCore/wtf/Forward.h index 67dc3be..448de7d 100644 --- a/JavaScriptCore/wtf/Forward.h +++ b/JavaScriptCore/wtf/Forward.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2006 Apple Computer, Inc. + * Copyright (C) 2006, 2009 Apple Inc. All rights reserved. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Library General Public @@ -27,6 +27,7 @@ namespace WTF { template<typename T> class ListRefPtr; template<typename T> class OwnArrayPtr; template<typename T> class OwnPtr; + template<typename T> class PassOwnPtr; template<typename T> class PassRefPtr; template<typename T> class RefPtr; template<typename T, size_t inlineCapacity> class Vector; @@ -35,9 +36,9 @@ namespace WTF { using WTF::ListRefPtr; using WTF::OwnArrayPtr; using WTF::OwnPtr; +using WTF::PassOwnPtr; using WTF::PassRefPtr; using WTF::RefPtr; using WTF::Vector; #endif // WTF_Forward_h - diff --git a/JavaScriptCore/wtf/GOwnPtr.h b/JavaScriptCore/wtf/GOwnPtr.h deleted file mode 100644 index 4993348..0000000 --- a/JavaScriptCore/wtf/GOwnPtr.h +++ /dev/null @@ -1,98 +0,0 @@ -/* - * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. - * Copyright (C) 2008 Collabora Ltd. - * - * 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 GOwnPtr_h -#define GOwnPtr_h - -#include <algorithm> -#include <glib.h> -#include <wtf/Assertions.h> -#include <wtf/Noncopyable.h> - -namespace WTF { - template <typename T> inline void freeOwnedGPtr(T* ptr) { g_free(reinterpret_cast<void*>(ptr)); } - template<> void freeOwnedGPtr<GError>(GError*); - template<> void freeOwnedGPtr<GList>(GList*); - template<> void freeOwnedGPtr<GCond>(GCond*); - template<> void freeOwnedGPtr<GMutex>(GMutex*); - template<> void freeOwnedGPtr<GPatternSpec>(GPatternSpec*); - template<> void freeOwnedGPtr<GDir>(GDir*); - template<> void freeOwnedGPtr<GHashTable>(GHashTable*); - - template <typename T> class GOwnPtr : public Noncopyable { - public: - explicit GOwnPtr(T* ptr = 0) : m_ptr(ptr) { } - ~GOwnPtr() { freeOwnedGPtr(m_ptr); } - - T* get() const { return m_ptr; } - T* release() { T* ptr = m_ptr; m_ptr = 0; return ptr; } - T*& outPtr() { ASSERT(!m_ptr); return m_ptr; } - - void set(T* ptr) { ASSERT(!ptr || m_ptr != ptr); freeOwnedGPtr(m_ptr); m_ptr = ptr; } - void clear() { freeOwnedGPtr(m_ptr); m_ptr = 0; } - - T& operator*() const { ASSERT(m_ptr); return *m_ptr; } - T* operator->() const { ASSERT(m_ptr); return m_ptr; } - - bool operator!() const { return !m_ptr; } - - // This conversion operator allows implicit conversion to bool but not to other integer types. - typedef T* GOwnPtr::*UnspecifiedBoolType; - operator UnspecifiedBoolType() const { return m_ptr ? &GOwnPtr::m_ptr : 0; } - - void swap(GOwnPtr& o) { std::swap(m_ptr, o.m_ptr); } - - private: - T* m_ptr; - }; - - template <typename T> inline void swap(GOwnPtr<T>& a, GOwnPtr<T>& b) { a.swap(b); } - - template <typename T, typename U> inline bool operator==(const GOwnPtr<T>& a, U* b) - { - return a.get() == b; - } - - template <typename T, typename U> inline bool operator==(T* a, const GOwnPtr<U>& b) - { - return a == b.get(); - } - - template <typename T, typename U> inline bool operator!=(const GOwnPtr<T>& a, U* b) - { - return a.get() != b; - } - - template <typename T, typename U> inline bool operator!=(T* a, const GOwnPtr<U>& b) - { - return a != b.get(); - } - - template <typename T> inline typename GOwnPtr<T>::PtrType getPtr(const GOwnPtr<T>& p) - { - return p.get(); - } - -} // namespace WTF - -using WTF::GOwnPtr; - -#endif // GOwnPtr_h diff --git a/JavaScriptCore/wtf/HashCountedSet.h b/JavaScriptCore/wtf/HashCountedSet.h index 1a422d8..165eb41 100644 --- a/JavaScriptCore/wtf/HashCountedSet.h +++ b/JavaScriptCore/wtf/HashCountedSet.h @@ -49,23 +49,28 @@ namespace WTF { const_iterator begin() const; const_iterator end() const; - iterator find(const ValueType& value); - const_iterator find(const ValueType& value) const; - bool contains(const ValueType& value) const; - unsigned count(const ValueType& value) const; + iterator find(const ValueType&); + const_iterator find(const ValueType&) const; + bool contains(const ValueType&) const; + unsigned count(const ValueType&) const; // increases the count if an equal value is already present // the return value is a pair of an interator to the new value's location, // and a bool that is true if an new entry was added - std::pair<iterator, bool> add(const ValueType &value); + std::pair<iterator, bool> add(const ValueType&); // reduces the count of the value, and removes it if count // goes down to zero - void remove(const ValueType& value); - void remove(iterator it); + void remove(const ValueType&); + void remove(iterator); - void clear(); - + // removes the value, regardless of its count + void removeAll(iterator); + void removeAll(const ValueType&); + + // clears the whole set + void clear(); + private: ImplType m_impl; }; @@ -166,6 +171,21 @@ namespace WTF { } template<typename Value, typename HashFunctions, typename Traits> + inline void HashCountedSet<Value, HashFunctions, Traits>::removeAll(const ValueType& value) + { + removeAll(find(value)); + } + + template<typename Value, typename HashFunctions, typename Traits> + inline void HashCountedSet<Value, HashFunctions, Traits>::removeAll(iterator it) + { + if (it == end()) + return; + + m_impl.remove(it); + } + + template<typename Value, typename HashFunctions, typename Traits> inline void HashCountedSet<Value, HashFunctions, Traits>::clear() { m_impl.clear(); diff --git a/JavaScriptCore/wtf/HashMap.h b/JavaScriptCore/wtf/HashMap.h index 3de5ee6..ece3812 100644 --- a/JavaScriptCore/wtf/HashMap.h +++ b/JavaScriptCore/wtf/HashMap.h @@ -83,6 +83,23 @@ namespace WTF { MappedType take(const KeyType&); // efficient combination of get with remove + // An alternate version of find() that finds the object by hashing and comparing + // with some other type, to avoid the cost of type conversion. HashTranslator + // must have the following function members: + // static unsigned hash(const T&); + // static bool equal(const ValueType&, const T&); + template<typename T, typename HashTranslator> iterator find(const T&); + template<typename T, typename HashTranslator> const_iterator find(const T&) const; + template<typename T, typename HashTranslator> bool contains(const T&) const; + + // An alternate version of add() that finds the object by hashing and comparing + // with some other type, to avoid the cost of type conversion if the object is already + // in the table. HashTranslator must have the following function members: + // static unsigned hash(const T&); + // static bool equal(const ValueType&, const T&); + // static translate(ValueType&, const T&, unsigned hashCode); + template<typename T, typename HashTranslator> pair<iterator, bool> add(const T&, const MappedType&); + private: pair<iterator, bool> inlineAdd(const KeyType&, const MappedType&); @@ -107,6 +124,19 @@ namespace WTF { } }; + template<typename ValueType, typename ValueTraits, typename T, typename Translator> + struct HashMapTranslatorAdapter { + typedef typename ValueType::first_type KeyType; + typedef typename ValueType::second_type MappedType; + + static unsigned hash(const T& key) { return Translator::hash(key); } + static bool equal(const KeyType& a, const T& b) { return Translator::equal(a, b); } + static void translate(ValueType& location, const T& key, const MappedType&, unsigned hashCode) + { + Translator::translate(location.first, key, hashCode); + } + }; + template<typename T, typename U, typename V, typename W, typename X> inline void HashMap<T, U, V, W, X>::swap(HashMap& other) { @@ -174,6 +204,33 @@ namespace WTF { } template<typename T, typename U, typename V, typename W, typename X> + template<typename TYPE, typename HashTranslator> + inline typename HashMap<T, U, V, W, X>::iterator + HashMap<T, U, V, W, X>::find(const TYPE& value) + { + typedef HashMapTranslatorAdapter<ValueType, ValueTraits, TYPE, HashTranslator> Adapter; + return m_impl.template find<TYPE, Adapter>(value); + } + + template<typename T, typename U, typename V, typename W, typename X> + template<typename TYPE, typename HashTranslator> + inline typename HashMap<T, U, V, W, X>::const_iterator + HashMap<T, U, V, W, X>::find(const TYPE& value) const + { + typedef HashMapTranslatorAdapter<ValueType, ValueTraits, TYPE, HashTranslator> Adapter; + return m_impl.template find<TYPE, Adapter>(value); + } + + template<typename T, typename U, typename V, typename W, typename X> + template<typename TYPE, typename HashTranslator> + inline bool + HashMap<T, U, V, W, X>::contains(const TYPE& value) const + { + typedef HashMapTranslatorAdapter<ValueType, ValueTraits, TYPE, HashTranslator> Adapter; + return m_impl.template contains<TYPE, Adapter>(value); + } + + template<typename T, typename U, typename V, typename W, typename X> inline pair<typename HashMap<T, U, V, W, X>::iterator, bool> HashMap<T, U, V, W, X>::inlineAdd(const KeyType& key, const MappedType& mapped) { @@ -194,6 +251,15 @@ namespace WTF { } template<typename T, typename U, typename V, typename W, typename X> + template<typename TYPE, typename HashTranslator> + pair<typename HashMap<T, U, V, W, X>::iterator, bool> + HashMap<T, U, V, W, X>::add(const TYPE& key, const MappedType& value) + { + typedef HashMapTranslatorAdapter<ValueType, ValueTraits, TYPE, HashTranslator> Adapter; + return m_impl.template addPassingHashCode<TYPE, MappedType, Adapter>(key, value); + } + + template<typename T, typename U, typename V, typename W, typename X> pair<typename HashMap<T, U, V, W, X>::iterator, bool> HashMap<T, U, V, W, X>::add(const KeyType& key, const MappedType& mapped) { diff --git a/JavaScriptCore/wtf/HashSet.h b/JavaScriptCore/wtf/HashSet.h index 990670d..0d7b4bb 100644 --- a/JavaScriptCore/wtf/HashSet.h +++ b/JavaScriptCore/wtf/HashSet.h @@ -29,6 +29,8 @@ namespace WTF { template<typename Value, typename HashFunctions, typename Traits> class HashSet; template<typename Value, typename HashFunctions, typename Traits> void deleteAllValues(const HashSet<Value, HashFunctions, Traits>&); + template<typename Value, typename HashFunctions, typename Traits> + void fastDeleteAllValues(const HashSet<Value, HashFunctions, Traits>&); template<typename T> struct IdentityExtractor; @@ -79,7 +81,7 @@ namespace WTF { // An alternate version of add() that finds the object by hashing and comparing // with some other type, to avoid the cost of type conversion if the object is already - // in the table. HashTranslator must have the following methods: + // in the table. HashTranslator must have the following function members: // static unsigned hash(const T&); // static bool equal(const ValueType&, const T&); // static translate(ValueType&, const T&, unsigned hashCode); @@ -91,6 +93,7 @@ namespace WTF { private: friend void deleteAllValues<>(const HashSet&); + friend void fastDeleteAllValues<>(const HashSet&); HashTableType m_impl; }; @@ -251,6 +254,21 @@ namespace WTF { { deleteAllValues<typename HashSet<T, U, V>::ValueType>(collection.m_impl); } + + template<typename ValueType, typename HashTableType> + void fastDeleteAllValues(HashTableType& collection) + { + typedef typename HashTableType::const_iterator iterator; + iterator end = collection.end(); + for (iterator it = collection.begin(); it != end; ++it) + fastDelete(*it); + } + + template<typename T, typename U, typename V> + inline void fastDeleteAllValues(const HashSet<T, U, V>& collection) + { + fastDeleteAllValues<typename HashSet<T, U, V>::ValueType>(collection.m_impl); + } template<typename T, typename U, typename V, typename W> inline void copyToVector(const HashSet<T, U, V>& collection, W& vector) diff --git a/JavaScriptCore/wtf/ListHashSet.h b/JavaScriptCore/wtf/ListHashSet.h index 38cc998..54ed36b 100644 --- a/JavaScriptCore/wtf/ListHashSet.h +++ b/JavaScriptCore/wtf/ListHashSet.h @@ -51,7 +51,7 @@ namespace WTF { template<typename ValueArg> struct ListHashSetNodeAllocator; template<typename ValueArg, typename HashArg> struct ListHashSetNodeHashFunctions; - template<typename ValueArg, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet { + template<typename ValueArg, typename HashArg = typename DefaultHash<ValueArg>::Hash> class ListHashSet : public FastAllocBase { private: typedef ListHashSetNode<ValueArg> Node; typedef ListHashSetNodeAllocator<ValueArg> NodeAllocator; diff --git a/JavaScriptCore/wtf/ListRefPtr.h b/JavaScriptCore/wtf/ListRefPtr.h index 9f9a354..8bf6447 100644 --- a/JavaScriptCore/wtf/ListRefPtr.h +++ b/JavaScriptCore/wtf/ListRefPtr.h @@ -34,13 +34,8 @@ namespace WTF { ListRefPtr(const RefPtr<T>& o) : RefPtr<T>(o) {} // see comment in PassRefPtr.h for why this takes const reference template <typename U> ListRefPtr(const PassRefPtr<U>& o) : RefPtr<T>(o) {} - - ~ListRefPtr() - { - RefPtr<T> reaper = this->release(); - while (reaper && reaper->hasOneRef()) - reaper = reaper->releaseNext(); // implicitly protects reaper->next, then derefs reaper - } + + ~ListRefPtr(); ListRefPtr& operator=(T* optr) { RefPtr<T>::operator=(optr); return *this; } ListRefPtr& operator=(const RefPtr<T>& o) { RefPtr<T>::operator=(o); return *this; } @@ -49,6 +44,20 @@ namespace WTF { template <typename U> ListRefPtr& operator=(const PassRefPtr<U>& o) { RefPtr<T>::operator=(o); return *this; } }; + // Remove inline for winscw compiler to prevent the compiler agressively resolving + // T::ref() in RefPtr<T>'s copy constructor. The bug is reported at: + // https://xdabug001.ext.nokia.com/bugzilla/show_bug.cgi?id=9812. + template <typename T> +#if !COMPILER(WINSCW) + inline +#endif + ListRefPtr<T>::~ListRefPtr() + { + RefPtr<T> reaper = this->release(); + while (reaper && reaper->hasOneRef()) + reaper = reaper->releaseNext(); // implicitly protects reaper->next, then derefs reaper + } + template <typename T> inline T* getPtr(const ListRefPtr<T>& p) { return p.get(); diff --git a/JavaScriptCore/wtf/MainThread.cpp b/JavaScriptCore/wtf/MainThread.cpp index e999094..40a4ae5 100644 --- a/JavaScriptCore/wtf/MainThread.cpp +++ b/JavaScriptCore/wtf/MainThread.cpp @@ -39,10 +39,12 @@ namespace WTF { struct FunctionWithContext { MainThreadFunction* function; void* context; + ThreadCondition* syncFlag; - FunctionWithContext(MainThreadFunction* function = 0, void* context = 0) + FunctionWithContext(MainThreadFunction* function = 0, void* context = 0, ThreadCondition* syncFlag = 0) : function(function) , context(context) + , syncFlag(syncFlag) { } }; @@ -92,6 +94,8 @@ void dispatchFunctionsFromMainThread() } invocation.function(invocation.context); + if (invocation.syncFlag) + invocation.syncFlag->signal(); // If we are running accumulated functions for too long so UI may become unresponsive, we need to // yield so the user input can be processed. Otherwise user may not be able to even close the window. @@ -117,6 +121,24 @@ void callOnMainThread(MainThreadFunction* function, void* context) scheduleDispatchFunctionsOnMainThread(); } +void callOnMainThreadAndWait(MainThreadFunction* function, void* context) +{ + ASSERT(function); + + if (isMainThread()) { + function(context); + return; + } + + ThreadCondition syncFlag; + Mutex& functionQueueMutex = mainThreadFunctionQueueMutex(); + MutexLocker locker(functionQueueMutex); + functionQueue().append(FunctionWithContext(function, context, &syncFlag)); + if (functionQueue().size() == 1) + scheduleDispatchFunctionsOnMainThread(); + syncFlag.wait(functionQueueMutex); +} + void setMainThreadCallbacksPaused(bool paused) { ASSERT(isMainThread()); diff --git a/JavaScriptCore/wtf/MainThread.h b/JavaScriptCore/wtf/MainThread.h index 01ce804..8c0275b 100644 --- a/JavaScriptCore/wtf/MainThread.h +++ b/JavaScriptCore/wtf/MainThread.h @@ -38,6 +38,9 @@ typedef void MainThreadFunction(void*); void callOnMainThread(MainThreadFunction*, void* context); +// Blocks the thread until the call finishes on the main thread. Misusing this can easily cause deadlocks. +void callOnMainThreadAndWait(MainThreadFunction*, void* context); + void setMainThreadCallbacksPaused(bool paused); // Must be called from the main thread (Darwin is an exception to this rule). @@ -52,6 +55,7 @@ void dispatchFunctionsFromMainThread(); } // namespace WTF using WTF::callOnMainThread; +using WTF::callOnMainThreadAndWait; using WTF::setMainThreadCallbacksPaused; #endif // MainThread_h diff --git a/JavaScriptCore/wtf/MathExtras.h b/JavaScriptCore/wtf/MathExtras.h index 324300d..ee2110e 100644 --- a/JavaScriptCore/wtf/MathExtras.h +++ b/JavaScriptCore/wtf/MathExtras.h @@ -26,6 +26,7 @@ #ifndef WTF_MathExtras_h #define WTF_MathExtras_h +#include <float.h> #include <math.h> #include <stdlib.h> @@ -43,11 +44,6 @@ #include <stdlib.h> #endif #include <limits> - -#if HAVE(FLOAT_H) -#include <float.h> -#endif - #endif #ifndef M_PI @@ -102,6 +98,8 @@ inline bool signbit(double x) { struct ieee_double *p = (struct ieee_double *)&x #if COMPILER(MSVC) || COMPILER(RVCT) +inline long long llround(double num) { return static_cast<long long>(num > 0 ? num + 0.5 : ceil(num - 0.5)); } +inline long long llroundf(float num) { return static_cast<long long>(num > 0 ? num + 0.5f : ceil(num - 0.5f)); } inline long lround(double num) { return static_cast<long>(num > 0 ? num + 0.5 : ceil(num - 0.5)); } inline long lroundf(float num) { return static_cast<long>(num > 0 ? num + 0.5f : ceilf(num - 0.5f)); } inline double round(double num) { return num > 0 ? floor(num + 0.5) : ceil(num - 0.5); } diff --git a/JavaScriptCore/wtf/MessageQueue.h b/JavaScriptCore/wtf/MessageQueue.h index 12291cc..48bd10a 100644 --- a/JavaScriptCore/wtf/MessageQueue.h +++ b/JavaScriptCore/wtf/MessageQueue.h @@ -44,20 +44,28 @@ namespace WTF { MessageQueueMessageReceived, // A message was successfully received and returned. }; + // The queue takes ownership of messages and transfer it to the new owner + // when messages are fetched from the queue. + // Essentially, MessageQueue acts as a queue of OwnPtr<DataType>. template<typename DataType> class MessageQueue : public Noncopyable { public: MessageQueue() : m_killed(false) { } - - void append(const DataType&); - bool appendAndCheckEmpty(const DataType&); - void prepend(const DataType&); - bool waitForMessage(DataType&); + ~MessageQueue(); + + void append(PassOwnPtr<DataType>); + bool appendAndCheckEmpty(PassOwnPtr<DataType>); + void prepend(PassOwnPtr<DataType>); + + PassOwnPtr<DataType> waitForMessage(); + PassOwnPtr<DataType> tryGetMessage(); template<typename Predicate> - MessageQueueWaitResult waitForMessageFilteredWithTimeout(DataType&, Predicate&, double absoluteTime); - void kill(); + PassOwnPtr<DataType> waitForMessageFilteredWithTimeout(MessageQueueWaitResult&, Predicate&, double absoluteTime); + + template<typename Predicate> + void removeIf(Predicate&); - bool tryGetMessage(DataType&); + void kill(); bool killed() const; // The result of isEmpty() is only valid if no other thread is manipulating the queue at the same time. @@ -66,86 +74,115 @@ namespace WTF { static double infiniteTime() { return std::numeric_limits<double>::max(); } private: - static bool alwaysTruePredicate(DataType&) { return true; } + static bool alwaysTruePredicate(DataType*) { return true; } mutable Mutex m_mutex; ThreadCondition m_condition; - Deque<DataType> m_queue; + Deque<DataType*> m_queue; bool m_killed; }; template<typename DataType> - inline void MessageQueue<DataType>::append(const DataType& message) + MessageQueue<DataType>::~MessageQueue() + { + deleteAllValues(m_queue); + } + + template<typename DataType> + inline void MessageQueue<DataType>::append(PassOwnPtr<DataType> message) { MutexLocker lock(m_mutex); - m_queue.append(message); + m_queue.append(message.release()); m_condition.signal(); } // Returns true if the queue was empty before the item was added. template<typename DataType> - inline bool MessageQueue<DataType>::appendAndCheckEmpty(const DataType& message) + inline bool MessageQueue<DataType>::appendAndCheckEmpty(PassOwnPtr<DataType> message) { MutexLocker lock(m_mutex); bool wasEmpty = m_queue.isEmpty(); - m_queue.append(message); + m_queue.append(message.release()); m_condition.signal(); return wasEmpty; } template<typename DataType> - inline void MessageQueue<DataType>::prepend(const DataType& message) + inline void MessageQueue<DataType>::prepend(PassOwnPtr<DataType> message) { MutexLocker lock(m_mutex); - m_queue.prepend(message); + m_queue.prepend(message.release()); m_condition.signal(); } template<typename DataType> - inline bool MessageQueue<DataType>::waitForMessage(DataType& result) + inline PassOwnPtr<DataType> MessageQueue<DataType>::waitForMessage() { - MessageQueueWaitResult exitReason = waitForMessageFilteredWithTimeout(result, MessageQueue<DataType>::alwaysTruePredicate, infiniteTime()); + MessageQueueWaitResult exitReason; + PassOwnPtr<DataType> result = waitForMessageFilteredWithTimeout(exitReason, MessageQueue<DataType>::alwaysTruePredicate, infiniteTime()); ASSERT(exitReason == MessageQueueTerminated || exitReason == MessageQueueMessageReceived); - return exitReason == MessageQueueMessageReceived; + return result; } template<typename DataType> template<typename Predicate> - inline MessageQueueWaitResult MessageQueue<DataType>::waitForMessageFilteredWithTimeout(DataType& result, Predicate& predicate, double absoluteTime) + inline PassOwnPtr<DataType> MessageQueue<DataType>::waitForMessageFilteredWithTimeout(MessageQueueWaitResult& result, Predicate& predicate, double absoluteTime) { MutexLocker lock(m_mutex); bool timedOut = false; - DequeConstIterator<DataType> found = m_queue.end(); + DequeConstIterator<DataType*> found = m_queue.end(); while (!m_killed && !timedOut && (found = m_queue.findIf(predicate)) == m_queue.end()) timedOut = !m_condition.timedWait(m_mutex, absoluteTime); ASSERT(!timedOut || absoluteTime != infiniteTime()); - if (m_killed) - return MessageQueueTerminated; + if (m_killed) { + result = MessageQueueTerminated; + return 0; + } - if (timedOut) - return MessageQueueTimeout; + if (timedOut) { + result = MessageQueueTimeout; + return 0; + } ASSERT(found != m_queue.end()); - result = *found; + DataType* message = *found; m_queue.remove(found); - return MessageQueueMessageReceived; + result = MessageQueueMessageReceived; + return message; } template<typename DataType> - inline bool MessageQueue<DataType>::tryGetMessage(DataType& result) + inline PassOwnPtr<DataType> MessageQueue<DataType>::tryGetMessage() { MutexLocker lock(m_mutex); if (m_killed) - return false; + return 0; if (m_queue.isEmpty()) - return false; + return 0; - result = m_queue.first(); + DataType* message = m_queue.first(); m_queue.removeFirst(); - return true; + return message; + } + + template<typename DataType> + template<typename Predicate> + inline void MessageQueue<DataType>::removeIf(Predicate& predicate) + { + MutexLocker lock(m_mutex); + // See bug 31657 for why this loop looks so weird + while (true) { + DequeConstIterator<DataType*> found = m_queue.findIf(predicate); + if (found == m_queue.end()) + break; + + DataType* message = *found; + m_queue.remove(found); + delete message; + } } template<typename DataType> diff --git a/JavaScriptCore/wtf/PassRefPtr.h b/JavaScriptCore/wtf/PassRefPtr.h index d80ed62..36ba78e 100644 --- a/JavaScriptCore/wtf/PassRefPtr.h +++ b/JavaScriptCore/wtf/PassRefPtr.h @@ -28,6 +28,19 @@ namespace WTF { template<typename T> class RefPtr; template<typename T> class PassRefPtr; template <typename T> PassRefPtr<T> adoptRef(T*); + + // Remove inline for winscw compiler to prevent the compiler agressively resolving + // T::deref(), which will fail compiling when PassRefPtr<T> is used as class member + // or function arguments before T is defined. + template<typename T> +#if !COMPILER(WINSCW) + inline +#endif + void derefIfNotNull(T* ptr) + { + if (UNLIKELY(ptr != 0)) + ptr->deref(); + } template<typename T> class PassRefPtr { public: @@ -40,8 +53,8 @@ namespace WTF { PassRefPtr(const PassRefPtr& o) : m_ptr(o.releaseRef()) {} template <typename U> PassRefPtr(const PassRefPtr<U>& o) : m_ptr(o.releaseRef()) { } - ALWAYS_INLINE ~PassRefPtr() { if (UNLIKELY(m_ptr != 0)) m_ptr->deref(); } - + ALWAYS_INLINE ~PassRefPtr() { derefIfNotNull<T>(m_ptr); } + template <class U> PassRefPtr(const RefPtr<U>& o) : m_ptr(o.get()) { if (T* ptr = m_ptr) ptr->ref(); } @@ -56,12 +69,9 @@ namespace WTF { bool operator!() const { return !m_ptr; } // This conversion operator allows implicit conversion to bool but not to other integer types. -#if COMPILER(WINSCW) - operator bool() const { return m_ptr; } -#else - typedef T* PassRefPtr::*UnspecifiedBoolType; + typedef T* (PassRefPtr::*UnspecifiedBoolType); operator UnspecifiedBoolType() const { return m_ptr ? &PassRefPtr::m_ptr : 0; } -#endif + PassRefPtr& operator=(T*); PassRefPtr& operator=(const PassRefPtr&); template <typename U> PassRefPtr& operator=(const PassRefPtr<U>&); @@ -74,6 +84,62 @@ namespace WTF { mutable T* m_ptr; }; + // NonNullPassRefPtr: Optimized for passing non-null pointers. A NonNullPassRefPtr + // begins life non-null, and can only become null through a call to releaseRef() + // or clear(). + + // FIXME: NonNullPassRefPtr could just inherit from PassRefPtr. However, + // if we use inheritance, GCC's optimizer fails to realize that destruction + // of a released NonNullPassRefPtr is a no-op. So, for now, just copy the + // most important code from PassRefPtr. + template <typename T> class NonNullPassRefPtr { + public: + NonNullPassRefPtr(T* ptr) + : m_ptr(ptr) + { + ASSERT(m_ptr); + m_ptr->ref(); + } + + template <class U> NonNullPassRefPtr(const RefPtr<U>& o) + : m_ptr(o.get()) + { + ASSERT(m_ptr); + m_ptr->ref(); + } + + NonNullPassRefPtr(const NonNullPassRefPtr& o) + : m_ptr(o.releaseRef()) + { + ASSERT(m_ptr); + } + + template <class U> NonNullPassRefPtr(const NonNullPassRefPtr<U>& o) + : m_ptr(o.releaseRef()) + { + ASSERT(m_ptr); + } + + template <class U> NonNullPassRefPtr(const PassRefPtr<U>& o) + : m_ptr(o.releaseRef()) + { + ASSERT(m_ptr); + } + + ALWAYS_INLINE ~NonNullPassRefPtr() { derefIfNotNull(m_ptr); } + + T* get() const { return m_ptr; } + + void clear() { derefIfNotNull(m_ptr); m_ptr = 0; } + T* releaseRef() const { T* tmp = m_ptr; m_ptr = 0; return tmp; } + + T& operator*() const { return *m_ptr; } + T* operator->() const { return m_ptr; } + + private: + mutable T* m_ptr; + }; + template <typename T> template <typename U> inline PassRefPtr<T>& PassRefPtr<T>::operator=(const RefPtr<U>& o) { T* optr = o.get(); @@ -188,6 +254,7 @@ namespace WTF { } // namespace WTF using WTF::PassRefPtr; +using WTF::NonNullPassRefPtr; using WTF::adoptRef; using WTF::static_pointer_cast; using WTF::const_pointer_cast; diff --git a/JavaScriptCore/wtf/Platform.h b/JavaScriptCore/wtf/Platform.h index 845684e..960b253 100644 --- a/JavaScriptCore/wtf/Platform.h +++ b/JavaScriptCore/wtf/Platform.h @@ -47,6 +47,11 @@ #elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_6 #define BUILDING_ON_LEOPARD 1 #endif +#if !defined(MAC_OS_X_VERSION_10_5) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_5 +#define TARGETING_TIGER 1 +#elif !defined(MAC_OS_X_VERSION_10_6) || MAC_OS_X_VERSION_MIN_REQUIRED < MAC_OS_X_VERSION_10_6 +#define TARGETING_LEOPARD 1 +#endif #include <TargetConditionals.h> #endif @@ -108,6 +113,13 @@ #define WTF_PLATFORM_NETBSD 1 #endif +/* PLATFORM(QNX) */ +/* Operating system level dependencies for QNX that should be used */ +/* regardless of operating environment */ +#if defined(__QNXNTO__) +#define WTF_PLATFORM_QNX 1 +#endif + /* PLATFORM(UNIX) */ /* Operating system level dependencies for Unix-like systems that */ /* should be used regardless of operating environment */ @@ -118,7 +130,10 @@ || defined(unix) \ || defined(__unix) \ || defined(__unix__) \ - || defined(_AIX) + || defined(_AIX) \ + || defined(__HAIKU__) \ + || defined(__QNXNTO__) \ + || defined(ANDROID) #define WTF_PLATFORM_UNIX 1 #endif @@ -126,23 +141,21 @@ /* PLATFORM(CHROMIUM) */ /* PLATFORM(QT) */ +/* PLATFORM(WX) */ /* PLATFORM(GTK) */ +/* PLATFORM(HAIKU) */ /* PLATFORM(MAC) */ /* PLATFORM(WIN) */ #if defined(BUILDING_CHROMIUM__) #define WTF_PLATFORM_CHROMIUM 1 #elif defined(BUILDING_QT__) #define WTF_PLATFORM_QT 1 - -/* PLATFORM(KDE) */ -#if defined(BUILDING_KDE__) -#define WTF_PLATFORM_KDE 1 -#endif - #elif defined(BUILDING_WX__) #define WTF_PLATFORM_WX 1 #elif defined(BUILDING_GTK__) #define WTF_PLATFORM_GTK 1 +#elif defined(BUILDING_HAIKU__) +#define WTF_PLATFORM_HAIKU 1 #elif PLATFORM(DARWIN) #define WTF_PLATFORM_MAC 1 #elif PLATFORM(WIN_OS) @@ -166,6 +179,11 @@ #define WTF_PLATFORM_IPHONE 0 #endif +/* PLATFORM(ANDROID) */ +#if defined(ANDROID) +#define WTF_PLATFORM_ANDROID 1 +#endif + /* Graphics engines */ /* PLATFORM(CG) and PLATFORM(CI) */ @@ -189,35 +207,10 @@ /* Makes PLATFORM(WIN) default to PLATFORM(CAIRO) */ /* FIXME: This should be changed from a blacklist to a whitelist */ -#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(WX) && !PLATFORM(CHROMIUM) && !PLATFORM(WINCE) +#if !PLATFORM(MAC) && !PLATFORM(QT) && !PLATFORM(WX) && !PLATFORM(CHROMIUM) && !PLATFORM(WINCE) && !PLATFORM(HAIKU) && !PLATFORM(ANDROID) #define WTF_PLATFORM_CAIRO 1 #endif -#ifdef ANDROID -#define WTF_PLATFORM_ANDROID 1 -#define WTF_PLATFORM_LINUX 1 -//due to pthread code in collector.cpp, we need PLATFORM(DARWIN) -//#undef WTF_PLATFORM_DARWIN -#undef WTF_PLATFORM_MAC -#undef WTF_PLATFORM_WIN_OS -#undef WTF_PLATFORM_WIN -#undef WTF_PLATFORM_CG -#undef WTF_PLATFORM_CI -#undef WTF_PLATFORM_CAIRO -#define WTF_USE_PTHREADS 1 - -#define WTF_PLATFORM_SGL 1 -#define WTF_PLATFORM_UNIX 1 - -#define USE_SYSTEM_MALLOC 1 -#define ENABLE_MAC_JAVA_BRIDGE 1 -#define LOG_DISABLED 1 -// Prevents Webkit from drawing the caret in textfields and textareas -// This prevents unnecessary invals. -#define ENABLE_TEXT_CARET 1 -#define ENABLE_JAVASCRIPT_DEBUGGER 0 -#endif // ANDROID - /* CPU */ /* PLATFORM(PPC) */ @@ -232,6 +225,16 @@ #define WTF_PLATFORM_BIG_ENDIAN 1 #endif +/* PLATFORM(SPARC32) */ +#if defined(__sparc) && !defined(__arch64__) || defined(__sparcv8) +#define WTF_PLATFORM_SPARC32 1 +#define WTF_PLATFORM_BIG_ENDIAN 1 +#endif + +#if PLATFORM(SPARC32) || PLATFORM(SPARC64) +#define WTF_PLATFORM_SPARC +#endif + /* PLATFORM(PPC64) */ #if defined(__ppc64__) \ || defined(__PPC64__) @@ -240,42 +243,112 @@ #endif /* PLATFORM(ARM) */ +#define PLATFORM_ARM_ARCH(N) (PLATFORM(ARM) && ARM_ARCH_VERSION >= N) + #if defined(arm) \ || defined(__arm__) #define WTF_PLATFORM_ARM 1 + #if defined(__ARMEB__) #define WTF_PLATFORM_BIG_ENDIAN 1 -#elif !defined(__ARM_EABI__) && !defined(__EABI__) && !defined(__VFP_FP__) -#if !defined(ANDROID) + +#elif !defined(__ARM_EABI__) \ + && !defined(__EABI__) \ + && !defined(__VFP_FP__) \ + && !defined(ANDROID) #define WTF_PLATFORM_MIDDLE_ENDIAN 1 + #endif -#endif -#if !defined(__ARM_EABI__) && !defined(__EABI__) -#define WTF_PLATFORM_FORCE_PACK 1 -#endif -#define ARM_ARCH_VERSION 3 -#if defined(__ARM_ARCH_4__) || defined(__ARM_ARCH_4T__) -#undef ARM_ARCH_VERSION + +/* Set ARM_ARCH_VERSION */ +#if defined(__ARM_ARCH_4__) \ + || defined(__ARM_ARCH_4T__) \ + || defined(__MARM_ARMV4__) \ + || defined(_ARMV4I_) #define ARM_ARCH_VERSION 4 -#endif -#if defined(__ARM_ARCH_5__) || defined(__ARM_ARCH_5T__) \ - || defined(__ARM_ARCH_5E__) || defined(__ARM_ARCH_5TE__) \ - || defined(__ARM_ARCH_5TEJ__) -#undef ARM_ARCH_VERSION + +#elif defined(__ARM_ARCH_5__) \ + || defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5E__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) \ + || defined(__MARM_ARMV5__) #define ARM_ARCH_VERSION 5 -#endif -#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) \ - || defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) \ - || defined(__ARM_ARCH_6ZK__) -#undef ARM_ARCH_VERSION + +#elif defined(__ARM_ARCH_6__) \ + || defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6T2__) \ + || defined(__ARMV6__) #define ARM_ARCH_VERSION 6 -#endif -#if defined(__ARM_ARCH_7A__) -#undef ARM_ARCH_VERSION + +#elif defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) #define ARM_ARCH_VERSION 7 + +/* RVCT sets _TARGET_ARCH_ARM */ +#elif defined(__TARGET_ARCH_ARM) +#define ARM_ARCH_VERSION __TARGET_ARCH_ARM + +#else +#define ARM_ARCH_VERSION 0 + #endif + +/* Set THUMB_ARM_VERSION */ +#if defined(__ARM_ARCH_4T__) +#define THUMB_ARCH_VERSION 1 + +#elif defined(__ARM_ARCH_5T__) \ + || defined(__ARM_ARCH_5TE__) \ + || defined(__ARM_ARCH_5TEJ__) +#define THUMB_ARCH_VERSION 2 + +#elif defined(__ARM_ARCH_6J__) \ + || defined(__ARM_ARCH_6K__) \ + || defined(__ARM_ARCH_6Z__) \ + || defined(__ARM_ARCH_6ZK__) \ + || defined(__ARM_ARCH_6M__) +#define THUMB_ARCH_VERSION 3 + +#elif defined(__ARM_ARCH_6T2__) \ + || defined(__ARM_ARCH_7__) \ + || defined(__ARM_ARCH_7A__) \ + || defined(__ARM_ARCH_7R__) \ + || defined(__ARM_ARCH_7M__) +#define THUMB_ARCH_VERSION 4 + +/* RVCT sets __TARGET_ARCH_THUMB */ +#elif defined(__TARGET_ARCH_THUMB) +#define THUMB_ARCH_VERSION __TARGET_ARCH_THUMB + +#else +#define THUMB_ARCH_VERSION 0 +#endif + +/* On ARMv5 and below the natural alignment is required. */ +#if !defined(ARM_REQUIRE_NATURAL_ALIGNMENT) && ARM_ARCH_VERSION <= 5 +#define ARM_REQUIRE_NATURAL_ALIGNMENT 1 +#endif + +/* Defines two pseudo-platforms for ARM and Thumb-2 instruction set. */ +#if !defined(WTF_PLATFORM_ARM_TRADITIONAL) && !defined(WTF_PLATFORM_ARM_THUMB2) +# if defined(thumb2) || defined(__thumb2__) \ + || ((defined(__thumb) || defined(__thumb__)) && THUMB_ARCH_VERSION == 4) +# define WTF_PLATFORM_ARM_TRADITIONAL 0 +# define WTF_PLATFORM_ARM_THUMB2 1 +# elif PLATFORM_ARM_ARCH(4) +# define WTF_PLATFORM_ARM_TRADITIONAL 1 +# define WTF_PLATFORM_ARM_THUMB2 0 +# else +# error "Not supported ARM architecture" +# endif +#elif PLATFORM(ARM_TRADITIONAL) && PLATFORM(ARM_THUMB2) /* Sanity Check */ +# error "Cannot use both of WTF_PLATFORM_ARM_TRADITIONAL and WTF_PLATFORM_ARM_THUMB2 platforms" +#endif // !defined(ARM_TRADITIONAL) && !defined(ARM_THUMB2) #endif /* ARM */ -#define PLATFORM_ARM_ARCH(N) (PLATFORM(ARM) && ARM_ARCH_VERSION >= N) /* PLATFORM(X86) */ #if defined(__i386__) \ @@ -292,13 +365,23 @@ #define WTF_PLATFORM_X86_64 1 #endif +/* PLATFORM(IA64) */ +#if defined(__ia64__) +#define WTF_PLATFORM_IA64 1 +#endif + +/* PLATFORM(ALPHA) */ +#if defined(__alpha__) +#define WTF_PLATFORM_ALPHA 1 +#endif + /* PLATFORM(SH4) */ #if defined(__SH4__) #define WTF_PLATFORM_SH4 1 #endif /* PLATFORM(SPARC64) */ -#if defined(__sparc64__) +#if defined(__sparc__) && defined(__arch64__) || defined (__sparcv9) #define WTF_PLATFORM_SPARC64 1 #define WTF_PLATFORM_BIG_ENDIAN 1 #endif @@ -315,6 +398,8 @@ # if Q_BYTE_ORDER == Q_BIG_EDIAN # define WTF_PLATFORM_BIG_ENDIAN 1 # endif + +# include <ce_time.h> #endif /* Compiler */ @@ -361,7 +446,7 @@ #define WTF_COMPILER_WINSCW 1 #endif -#if (PLATFORM(IPHONE) || PLATFORM(MAC) || PLATFORM(WIN)) && !defined(ENABLE_JSC_MULTIPLE_THREADS) +#if (PLATFORM(IPHONE) || PLATFORM(MAC) || PLATFORM(WIN) || (PLATFORM(QT) && PLATFORM(DARWIN))) && !defined(ENABLE_JSC_MULTIPLE_THREADS) #define ENABLE_JSC_MULTIPLE_THREADS 1 #endif @@ -397,8 +482,7 @@ #endif /* PLATFORM(WINCE) && !PLATFORM(QT) */ -/* for Unicode, KDE uses Qt */ -#if PLATFORM(KDE) || PLATFORM(QT) +#if PLATFORM(QT) #define WTF_USE_QT4_UNICODE 1 #elif PLATFORM(WINCE) #define WTF_USE_WINCE_UNICODE 1 @@ -411,6 +495,10 @@ #if PLATFORM(MAC) && !PLATFORM(IPHONE) #define WTF_PLATFORM_CF 1 #define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 +#if !defined(BUILDING_ON_LEOPARD) && !defined(BUILDING_ON_TIGER) && defined(__x86_64__) +#define WTF_USE_PLUGIN_HOST_PROCESS 1 +#endif #if !defined(ENABLE_MAC_JAVA_BRIDGE) #define ENABLE_MAC_JAVA_BRIDGE 1 #endif @@ -419,24 +507,46 @@ #endif #define HAVE_READLINE 1 #define HAVE_RUNLOOP_TIMER 1 -#define HAVE_PTHREAD_RWLOCK 1 -#endif +#endif /* PLATFORM(MAC) && !PLATFORM(IPHONE) */ #if PLATFORM(CHROMIUM) && PLATFORM(DARWIN) #define WTF_PLATFORM_CF 1 #define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 #endif -#if PLATFORM(IPHONE) +#if PLATFORM(QT) && PLATFORM(DARWIN) #define WTF_PLATFORM_CF 1 -#define WTF_USE_PTHREADS 1 +#endif + +#if PLATFORM(IPHONE) +#define ENABLE_CONTEXT_MENUS 0 +#define ENABLE_DRAG_SUPPORT 0 #define ENABLE_FTPDIR 1 -#define ENABLE_MAC_JAVA_BRIDGE 0 -#define ENABLE_ICONDATABASE 0 #define ENABLE_GEOLOCATION 1 +#define ENABLE_ICONDATABASE 0 +#define ENABLE_INSPECTOR 0 +#define ENABLE_MAC_JAVA_BRIDGE 0 #define ENABLE_NETSCAPE_PLUGIN_API 0 -#define HAVE_READLINE 1 +#define ENABLE_ORIENTATION_EVENTS 1 #define ENABLE_REPAINT_THROTTLING 1 +#define HAVE_READLINE 1 +#define WTF_PLATFORM_CF 1 +#define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 +#endif + +#if PLATFORM(ANDROID) +#define WTF_USE_PTHREADS 1 +#define WTF_PLATFORM_SKIA 1 +#define USE_SYSTEM_MALLOC 1 +#define ENABLE_MAC_JAVA_BRIDGE 1 +#define LOG_DISABLED 1 +// Prevents Webkit from drawing the caret in textfields and textareas +// This prevents unnecessary invals. +#define ENABLE_TEXT_CARET 1 +#define ENABLE_JAVASCRIPT_DEBUGGER 0 +#define ENABLE_ORIENTATION_EVENTS 1 #endif #if PLATFORM(WIN) @@ -445,16 +555,27 @@ #if PLATFORM(WX) #define ENABLE_ASSEMBLER 1 -#define WTF_USE_CURL 1 -#define WTF_USE_PTHREADS 1 +#if PLATFORM(DARWIN) +#define WTF_PLATFORM_CF 1 +#endif #endif #if PLATFORM(GTK) #if HAVE(PTHREAD_H) #define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 #endif #endif +#if PLATFORM(HAIKU) +#define HAVE_POSIX_MEMALIGN 1 +#define WTF_USE_CURL 1 +#define WTF_USE_PTHREADS 1 +#define HAVE_PTHREAD_RWLOCK 1 +#define USE_SYSTEM_MALLOC 1 +#define ENABLE_NETSCAPE_PLUGIN_API 0 +#endif + #if !defined(HAVE_ACCESSIBILITY) #if PLATFORM(IPHONE) || PLATFORM(MAC) || PLATFORM(WIN) || PLATFORM(GTK) || PLATFORM(CHROMIUM) #define HAVE_ACCESSIBILITY 1 @@ -465,7 +586,9 @@ #define HAVE_SIGNAL_H 1 #endif -#if !PLATFORM(WIN_OS) && !PLATFORM(SOLARIS) && !PLATFORM(SYMBIAN) && !COMPILER(RVCT) && !PLATFORM(ANDROID) +#if !PLATFORM(WIN_OS) && !PLATFORM(SOLARIS) && !PLATFORM(QNX) \ + && !PLATFORM(SYMBIAN) && !PLATFORM(HAIKU) && !COMPILER(RVCT) \ + && !PLATFORM(ANDROID) #define HAVE_TM_GMTOFF 1 #define HAVE_TM_ZONE 1 #define HAVE_TIMEGM 1 @@ -483,9 +606,10 @@ #define HAVE_SYS_TIME_H 1 #define HAVE_SYS_TIMEB_H 1 -#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !PLATFORM(IPHONE) +#if !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !PLATFORM(IPHONE) && !PLATFORM(QT) #define HAVE_MADV_FREE_REUSE 1 #define HAVE_MADV_FREE 1 +#define HAVE_PTHREAD_SETNAME_NP 1 #endif #if PLATFORM(IPHONE) @@ -494,7 +618,6 @@ #elif PLATFORM(WIN_OS) -#define HAVE_FLOAT_H 1 #if PLATFORM(WINCE) #define HAVE_ERRNO_H 0 #else @@ -515,6 +638,15 @@ #define HAVE_SYS_PARAM_H 1 #endif +#elif PLATFORM(QNX) + +#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 + #elif PLATFORM(ANDROID) #define HAVE_ERRNO_H 1 @@ -530,7 +662,10 @@ /* FIXME: is this actually used or do other platforms generate their own config.h? */ #define HAVE_ERRNO_H 1 +/* As long as Haiku doesn't have a complete support of locale this will be disabled. */ +#if !PLATFORM(HAIKU) #define HAVE_LANGINFO_H 1 +#endif #define HAVE_MMAP 1 #define HAVE_SBRK 1 #define HAVE_STRINGS_H 1 @@ -563,10 +698,22 @@ #define ENABLE_FTPDIR 1 #endif +#if !defined(ENABLE_CONTEXT_MENUS) +#define ENABLE_CONTEXT_MENUS 1 +#endif + +#if !defined(ENABLE_DRAG_SUPPORT) +#define ENABLE_DRAG_SUPPORT 1 +#endif + #if !defined(ENABLE_DASHBOARD_SUPPORT) #define ENABLE_DASHBOARD_SUPPORT 0 #endif +#if !defined(ENABLE_INSPECTOR) +#define ENABLE_INSPECTOR 1 +#endif + #if !defined(ENABLE_MAC_JAVA_BRIDGE) #define ENABLE_MAC_JAVA_BRIDGE 0 #endif @@ -575,6 +722,14 @@ #define ENABLE_NETSCAPE_PLUGIN_API 1 #endif +#if !defined(WTF_USE_PLUGIN_HOST_PROCESS) +#define WTF_USE_PLUGIN_HOST_PROCESS 0 +#endif + +#if !defined(ENABLE_ORIENTATION_EVENTS) +#define ENABLE_ORIENTATION_EVENTS 0 +#endif + #if !defined(ENABLE_OPCODE_STATS) #define ENABLE_OPCODE_STATS 0 #endif @@ -594,11 +749,17 @@ #define ENABLE_GEOLOCATION 0 #endif +#if !defined(ENABLE_NOTIFICATIONS) +#define ENABLE_NOTIFICATIONS 0 +#endif + #if !defined(ENABLE_TEXT_CARET) #define ENABLE_TEXT_CARET 1 #endif -// ANDROID addition: allow web archive to be disabled +// ENABLE_ARCHIVE is an Android addition. We need this default value to allow +// us to build on Mac. +// FIXME: Upstream to webkit.org. #if !defined(ENABLE_ARCHIVE) #define ENABLE_ARCHIVE 1 #endif @@ -608,9 +769,13 @@ #endif #if !defined(WTF_USE_JSVALUE64) && !defined(WTF_USE_JSVALUE32) && !defined(WTF_USE_JSVALUE32_64) -#if PLATFORM(X86_64) && (PLATFORM(MAC) || (PLATFORM(LINUX) && !PLATFORM(QT))) +#if (PLATFORM(X86_64) && (PLATFORM(UNIX) || PLATFORM(WIN_OS))) || PLATFORM(IA64) || PLATFORM(ALPHA) #define WTF_USE_JSVALUE64 1 -#elif PLATFORM(PPC64) || PLATFORM(QT) /* All Qt layout tests crash in JSVALUE32_64 mode. */ +#elif PLATFORM(ARM) || PLATFORM(PPC64) +#define WTF_USE_JSVALUE32 1 +#elif PLATFORM(WIN_OS) && COMPILER(MINGW) +/* Using JSVALUE32_64 causes padding/alignement issues for JITStubArg +on MinGW. See https://bugs.webkit.org/show_bug.cgi?id=29268 */ #define WTF_USE_JSVALUE32 1 #else #define WTF_USE_JSVALUE32_64 1 @@ -630,27 +795,32 @@ #elif PLATFORM(X86) && PLATFORM(MAC) #define ENABLE_JIT 1 #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 -#elif PLATFORM_ARM_ARCH(7) && PLATFORM(IPHONE) - /* Under development, temporarily disabled until 16Mb link range limit in assembler is fixed. */ - #define ENABLE_JIT 0 - #define ENABLE_JIT_OPTIMIZE_NATIVE_CALL 0 +#elif PLATFORM(ARM_THUMB2) && PLATFORM(IPHONE) + #define ENABLE_JIT 1 /* The JIT is tested & working on x86 Windows */ #elif PLATFORM(X86) && PLATFORM(WIN) #define ENABLE_JIT 1 #endif -#if PLATFORM(X86) && PLATFORM(QT) -#if PLATFORM(WIN_OS) && COMPILER(MINGW) && GCC_VERSION >= 40100 +#if PLATFORM(QT) +#if PLATFORM(X86_64) && PLATFORM(DARWIN) + #define ENABLE_JIT 1 +#elif PLATFORM(X86) && PLATFORM(DARWIN) #define ENABLE_JIT 1 #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 -#elif PLATFORM(WIN_OS) && COMPILER(MSVC) +#elif PLATFORM(X86) && PLATFORM(WIN_OS) && COMPILER(MINGW) && GCC_VERSION >= 40100 + #define ENABLE_JIT 1 + #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 +#elif PLATFORM(X86) && PLATFORM(WIN_OS) && COMPILER(MSVC) #define ENABLE_JIT 1 #define WTF_USE_JIT_STUB_ARGUMENT_REGISTER 1 -#elif PLATFORM(LINUX) && GCC_VERSION >= 40100 +#elif PLATFORM(X86) && PLATFORM(LINUX) && GCC_VERSION >= 40100 #define ENABLE_JIT 1 #define WTF_USE_JIT_STUB_ARGUMENT_VA_LIST 1 +#elif PLATFORM(ARM_TRADITIONAL) && PLATFORM(LINUX) + #define ENABLE_JIT 1 #endif -#endif /* PLATFORM(QT) && PLATFORM(X86) */ +#endif /* PLATFORM(QT) */ #endif /* !defined(ENABLE_JIT) */ @@ -693,17 +863,17 @@ /* YARR supports x86 & x86-64, and has been tested on Mac and Windows. */ #if (PLATFORM(X86) && PLATFORM(MAC)) \ || (PLATFORM(X86_64) && PLATFORM(MAC)) \ - /* Under development, temporarily disabled until 16Mb link range limit in assembler is fixed. */ \ - || (PLATFORM_ARM_ARCH(7) && PLATFORM(IPHONE) && 0) \ + || (PLATFORM(ARM_THUMB2) && PLATFORM(IPHONE)) \ || (PLATFORM(X86) && PLATFORM(WIN)) #define ENABLE_YARR 1 #define ENABLE_YARR_JIT 1 #endif -#if PLATFORM(X86) && PLATFORM(QT) -#if (PLATFORM(WIN_OS) && COMPILER(MINGW) && GCC_VERSION >= 40100) \ - || (PLATFORM(WIN_OS) && COMPILER(MSVC)) \ - || (PLATFORM(LINUX) && GCC_VERSION >= 40100) +#if PLATFORM(QT) +#if (PLATFORM(X86) && PLATFORM(WIN_OS) && COMPILER(MINGW) && GCC_VERSION >= 40100) \ + || (PLATFORM(X86) && PLATFORM(WIN_OS) && COMPILER(MSVC)) \ + || (PLATFORM(X86) && PLATFORM(LINUX) && GCC_VERSION >= 40100) \ + || (PLATFORM(ARM_TRADITIONAL) && PLATFORM(LINUX)) #define ENABLE_YARR 1 #define ENABLE_YARR_JIT 1 #endif @@ -731,15 +901,11 @@ #define ENABLE_PAN_SCROLLING 1 #endif -#if !defined(ENABLE_ACTIVEX_TYPE_CONVERSION_WMPLAYER) -#define ENABLE_ACTIVEX_TYPE_CONVERSION_WMPLAYER 1 -#endif - -/* Use the QtXmlStreamReader implementation for XMLTokenizer */ +/* Use the QXmlStreamReader implementation for XMLTokenizer */ +/* Use the QXmlQuery implementation for XSLTProcessor */ #if PLATFORM(QT) -#if !ENABLE(XSLT) #define WTF_USE_QXMLSTREAM 1 -#endif +#define WTF_USE_QXMLQUERY 1 #endif #if !PLATFORM(QT) @@ -753,8 +919,31 @@ #endif #endif +#if PLATFORM(ANDROID) +#define WTF_USE_ACCELERATED_COMPOSITING 0 +#endif + #if PLATFORM(IPHONE) #define WTF_USE_ACCELERATED_COMPOSITING 1 #endif +#if PLATFORM(WIN) +#define WTF_USE_ACCELERATED_COMPOSITING 0 +#endif + +#if COMPILER(GCC) +#define WARN_UNUSED_RETURN __attribute__ ((warn_unused_result)) +#else +#define WARN_UNUSED_RETURN +#endif + +#if !ENABLE(NETSCAPE_PLUGIN_API) || (ENABLE(NETSCAPE_PLUGIN_API) && ((PLATFORM(UNIX) && (PLATFORM(QT) || PLATFORM(WX))) || PLATFORM(GTK))) +#define ENABLE_PLUGIN_PACKAGE_SIMPLE_HASH 1 +#endif + +/* Set up a define for a common error that is intended to cause a build error -- thus the space after Error. */ +#define WTF_PLATFORM_CFNETWORK Error USE_macro_should_be_used_with_CFNETWORK + +#define ENABLE_JSC_ZOMBIES 0 + #endif /* WTF_Platform_h */ diff --git a/JavaScriptCore/wtf/PossiblyNull.h b/JavaScriptCore/wtf/PossiblyNull.h new file mode 100644 index 0000000..79c4d82 --- /dev/null +++ b/JavaScriptCore/wtf/PossiblyNull.h @@ -0,0 +1,59 @@ +/* + * Copyright (C) 2009 Apple Inc. All Rights Reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY APPLE INC. ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef PossiblyNull_h +#define PossiblyNull_h + +#include "Assertions.h" + +namespace WTF { + +template <typename T> struct PossiblyNull { + PossiblyNull(T data) + : m_data(data) + { + } + PossiblyNull(const PossiblyNull<T>& source) + : m_data(source.m_data) + { + source.m_data = 0; + } + ~PossiblyNull() { ASSERT(!m_data); } + bool getValue(T& out) WARN_UNUSED_RETURN; +private: + mutable T m_data; +}; + +template <typename T> bool PossiblyNull<T>::getValue(T& out) +{ + out = m_data; + bool result = !!m_data; + m_data = 0; + return result; +} + +} + +#endif diff --git a/JavaScriptCore/wtf/PtrAndFlags.h b/JavaScriptCore/wtf/PtrAndFlags.h index 485c595..1e1bee0 100644 --- a/JavaScriptCore/wtf/PtrAndFlags.h +++ b/JavaScriptCore/wtf/PtrAndFlags.h @@ -34,11 +34,8 @@ #include <wtf/Assertions.h> namespace WTF { - template<class T, typename FlagEnum> class PtrAndFlags { + template<class T, typename FlagEnum> class PtrAndFlagsBase { public: - PtrAndFlags() : m_ptrAndFlags(0) {} - PtrAndFlags(T* ptr) : m_ptrAndFlags(0) { set(ptr); } - bool isFlagSet(FlagEnum flagNumber) const { ASSERT(flagNumber < 2); return m_ptrAndFlags & (1 << flagNumber); } void setFlag(FlagEnum flagNumber) { ASSERT(flagNumber < 2); m_ptrAndFlags |= (1 << flagNumber);} void clearFlag(FlagEnum flagNumber) { ASSERT(flagNumber < 2); m_ptrAndFlags &= ~(1 << flagNumber);} @@ -55,14 +52,28 @@ namespace WTF { bool operator!() const { return !get(); } T* operator->() const { return reinterpret_cast<T*>(m_ptrAndFlags & ~3); } - private: + protected: intptr_t m_ptrAndFlags; #ifndef NDEBUG void* m_leaksPtr; // Only used to allow tools like leaks on OSX to detect that the memory is referenced. #endif }; + + template<class T, typename FlagEnum> class PtrAndFlags : public PtrAndFlagsBase<T, FlagEnum> { + public: + PtrAndFlags() + { + PtrAndFlagsBase<T, FlagEnum>::m_ptrAndFlags = 0; + } + PtrAndFlags(T* ptr) + { + PtrAndFlagsBase<T, FlagEnum>::m_ptrAndFlags = 0; + PtrAndFlagsBase<T, FlagEnum>::set(ptr); + } + }; } // namespace WTF +using WTF::PtrAndFlagsBase; using WTF::PtrAndFlags; #endif // PtrAndFlags_h diff --git a/JavaScriptCore/wtf/RandomNumber.cpp b/JavaScriptCore/wtf/RandomNumber.cpp index 0e6e208..52fb130 100644 --- a/JavaScriptCore/wtf/RandomNumber.cpp +++ b/JavaScriptCore/wtf/RandomNumber.cpp @@ -82,6 +82,23 @@ double randomNumber() return static_cast<double>(fullRandom)/static_cast<double>(1LL << 53); #elif PLATFORM(WINCE) return genrand_res53(); +#elif PLATFORM(WIN_OS) + uint32_t part1 = rand() & (RAND_MAX - 1); + uint32_t part2 = rand() & (RAND_MAX - 1); + uint32_t part3 = rand() & (RAND_MAX - 1); + uint32_t part4 = rand() & (RAND_MAX - 1); + // rand only provides 15 bits on Win32 + uint64_t fullRandom = part1; + fullRandom <<= 15; + fullRandom |= part2; + fullRandom <<= 15; + fullRandom |= part3; + fullRandom <<= 15; + fullRandom |= part4; + + // Mask off the low 53bits + fullRandom &= (1LL << 53) - 1; + return static_cast<double>(fullRandom)/static_cast<double>(1LL << 53); #else uint32_t part1 = rand() & (RAND_MAX - 1); uint32_t part2 = rand() & (RAND_MAX - 1); diff --git a/JavaScriptCore/wtf/RefPtr.h b/JavaScriptCore/wtf/RefPtr.h index 74cd0ea..e6d1047 100644 --- a/JavaScriptCore/wtf/RefPtr.h +++ b/JavaScriptCore/wtf/RefPtr.h @@ -30,6 +30,7 @@ namespace WTF { enum PlacementNewAdoptType { PlacementNewAdopt }; template <typename T> class PassRefPtr; + template <typename T> class NonNullPassRefPtr; enum HashTableDeletedValueType { HashTableDeletedValue }; @@ -40,6 +41,7 @@ namespace WTF { RefPtr(const RefPtr& o) : m_ptr(o.m_ptr) { if (T* ptr = m_ptr) ptr->ref(); } // see comment in PassRefPtr.h for why this takes const reference template <typename U> RefPtr(const PassRefPtr<U>&); + template <typename U> RefPtr(const NonNullPassRefPtr<U>&); // Special constructor for cases where we overwrite an object in place. RefPtr(PlacementNewAdoptType) { } @@ -73,8 +75,10 @@ namespace WTF { RefPtr& operator=(const RefPtr&); RefPtr& operator=(T*); RefPtr& operator=(const PassRefPtr<T>&); + RefPtr& operator=(const NonNullPassRefPtr<T>&); template <typename U> RefPtr& operator=(const RefPtr<U>&); template <typename U> RefPtr& operator=(const PassRefPtr<U>&); + template <typename U> RefPtr& operator=(const NonNullPassRefPtr<U>&); void swap(RefPtr&); @@ -89,6 +93,11 @@ namespace WTF { { } + template <typename T> template <typename U> inline RefPtr<T>::RefPtr(const NonNullPassRefPtr<U>& o) + : m_ptr(o.releaseRef()) + { + } + template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(const RefPtr<T>& o) { T* optr = o.get(); @@ -133,6 +142,15 @@ namespace WTF { return *this; } + template <typename T> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<T>& o) + { + T* ptr = m_ptr; + m_ptr = o.releaseRef(); + if (ptr) + ptr->deref(); + return *this; + } + template <typename T> template <typename U> inline RefPtr<T>& RefPtr<T>::operator=(const PassRefPtr<U>& o) { T* ptr = m_ptr; @@ -142,6 +160,15 @@ namespace WTF { return *this; } + template <typename T> template <typename U> inline RefPtr<T>& RefPtr<T>::operator=(const NonNullPassRefPtr<U>& o) + { + T* ptr = m_ptr; + m_ptr = o.releaseRef(); + if (ptr) + ptr->deref(); + return *this; + } + template <class T> inline void RefPtr<T>::swap(RefPtr<T>& o) { std::swap(m_ptr, o.m_ptr); diff --git a/JavaScriptCore/wtf/SegmentedVector.h b/JavaScriptCore/wtf/SegmentedVector.h index 065c19c..b1cbc4d 100644 --- a/JavaScriptCore/wtf/SegmentedVector.h +++ b/JavaScriptCore/wtf/SegmentedVector.h @@ -116,6 +116,7 @@ namespace WTF { } size_t size() const { return m_size; } + bool isEmpty() const { return !size(); } T& at(size_t index) { @@ -249,4 +250,6 @@ namespace WTF { } // namespace WTF +using WTF::SegmentedVector; + #endif // SegmentedVector_h diff --git a/JavaScriptCore/wtf/StdLibExtras.h b/JavaScriptCore/wtf/StdLibExtras.h index d21d1ff..dd90c85 100644 --- a/JavaScriptCore/wtf/StdLibExtras.h +++ b/JavaScriptCore/wtf/StdLibExtras.h @@ -32,6 +32,7 @@ // Use these to declare and define a static local variable (static T;) so that // it is leaked so that its destructors are not called at exit. Using this // macro also allows workarounds a compiler bug present in Apple's version of GCC 4.0.1. +#ifndef DEFINE_STATIC_LOCAL #if COMPILER(GCC) && defined(__APPLE_CC__) && __GNUC__ == 4 && __GNUC_MINOR__ == 0 && __GNUC_PATCHLEVEL__ == 1 #define DEFINE_STATIC_LOCAL(type, name, arguments) \ static type* name##Ptr = new type arguments; \ @@ -40,12 +41,17 @@ #define DEFINE_STATIC_LOCAL(type, name, arguments) \ static type& name = *new type arguments #endif +#endif // OBJECT_OFFSETOF: Like the C++ offsetof macro, but you can use it with classes. // The magic number 0x4000 is insignificant. We use it to avoid using NULL, since // NULL can cause compiler problems, especially in cases of multiple inheritance. #define OBJECT_OFFSETOF(class, field) (reinterpret_cast<ptrdiff_t>(&(reinterpret_cast<class*>(0x4000)->field)) - 0x4000) +// STRINGIZE: Can convert any value to quoted string, even expandable macros +#define STRINGIZE(exp) #exp +#define STRINGIZE_VALUE_OF(exp) STRINGIZE(exp) + namespace WTF { /* diff --git a/JavaScriptCore/wtf/StringExtras.h b/JavaScriptCore/wtf/StringExtras.h index 1c23390..50efe35 100644 --- a/JavaScriptCore/wtf/StringExtras.h +++ b/JavaScriptCore/wtf/StringExtras.h @@ -75,12 +75,28 @@ inline char* strdup(const char* strSource) inline int strncasecmp(const char* s1, const char* s2, size_t len) { - return strnicmp(s1, s2, len); + return _strnicmp(s1, s2, len); } inline int strcasecmp(const char* s1, const char* s2) { - return stricmp(s1, s2); + return _stricmp(s1, s2); +} + +#endif + +#if PLATFORM(WIN_OS) || PLATFORM(LINUX) || PLATFORM(SOLARIS) + +inline char* strnstr(const char* buffer, const char* target, size_t bufferLength) +{ + size_t targetLength = strlen(target); + if (targetLength == 0) + return const_cast<char*>(buffer); + for (const char* start = buffer; *start && start + targetLength <= buffer + bufferLength; start++) { + if (*start == *target && strncmp(start + 1, target + 1, targetLength - 1) == 0) + return const_cast<char*>(start); + } + return 0; } #endif diff --git a/JavaScriptCore/wtf/TCSpinLock.h b/JavaScriptCore/wtf/TCSpinLock.h index ced2283..4cf30c2 100644 --- a/JavaScriptCore/wtf/TCSpinLock.h +++ b/JavaScriptCore/wtf/TCSpinLock.h @@ -209,6 +209,13 @@ struct TCMalloc_SpinLock { inline void Unlock() { if (pthread_mutex_unlock(&private_lock_) != 0) CRASH(); } + bool IsHeld() { + if (pthread_mutex_trylock(&private_lock_)) + return true; + + Unlock(); + return false; + } }; #define SPINLOCK_INITIALIZER { PTHREAD_MUTEX_INITIALIZER } diff --git a/JavaScriptCore/wtf/ThreadSpecific.h b/JavaScriptCore/wtf/ThreadSpecific.h index 4d5d2f7..b6f5fd3 100644 --- a/JavaScriptCore/wtf/ThreadSpecific.h +++ b/JavaScriptCore/wtf/ThreadSpecific.h @@ -79,10 +79,13 @@ private: #if USE(PTHREADS) || PLATFORM(QT) || PLATFORM(WIN_OS) struct Data : Noncopyable { Data(T* value, ThreadSpecific<T>* owner) : value(value), owner(owner) {} +#if PLATFORM(QT) + ~Data() { owner->destroy(this); } +#endif T* value; ThreadSpecific<T>* owner; -#if !USE(PTHREADS) +#if !USE(PTHREADS) && !PLATFORM(QT) void (*destructor)(void*); #endif }; @@ -136,9 +139,7 @@ inline ThreadSpecific<T>::ThreadSpecific() template<typename T> inline ThreadSpecific<T>::~ThreadSpecific() { - Data* data = static_cast<Data*>(m_key.localData()); - if (data) - data->destructor(data); + // Does not invoke destructor functions. QThreadStorage will do it } template<typename T> @@ -153,7 +154,6 @@ inline void ThreadSpecific<T>::set(T* ptr) { ASSERT(!get()); Data* data = new Data(ptr, this); - data->destructor = &ThreadSpecific<T>::destroy; m_key.setLocalData(data); } @@ -218,21 +218,27 @@ inline void ThreadSpecific<T>::destroy(void* ptr) // Some pthreads implementations zero out the pointer before calling destroy(), so we temporarily reset it. pthread_setspecific(data->owner->m_key, ptr); #endif - +#if PLATFORM(QT) + // See comment as above + data->owner->m_key.setLocalData(data); +#endif + data->value->~T(); fastFree(data->value); #if USE(PTHREADS) pthread_setspecific(data->owner->m_key, 0); #elif PLATFORM(QT) - data->owner->m_key.setLocalData(0); + // Do nothing here #elif PLATFORM(WIN_OS) TlsSetValue(tlsKeys()[data->owner->m_index], 0); #else #error ThreadSpecific is not implemented for this platform. #endif +#if !PLATFORM(QT) delete data; +#endif } template<typename T> diff --git a/JavaScriptCore/wtf/Threading.cpp b/JavaScriptCore/wtf/Threading.cpp index 56bf438..74c47f4 100644 --- a/JavaScriptCore/wtf/Threading.cpp +++ b/JavaScriptCore/wtf/Threading.cpp @@ -51,7 +51,7 @@ static void* threadEntryPoint(void* contextData) setThreadNameInternal(context->name); - // Block until our creating thread has completed any extra setup work + // Block until our creating thread has completed any extra setup work. { MutexLocker locker(context->creationMutex); } @@ -75,7 +75,7 @@ ThreadIdentifier createThread(ThreadFunction entryPoint, void* data, const char* NewThreadContext* context = new NewThreadContext(entryPoint, data, name); - // Prevent the thread body from executing until we've established the thread identifier + // Prevent the thread body from executing until we've established the thread identifier. MutexLocker locker(context->creationMutex); return createThreadInternal(threadEntryPoint, context, name); diff --git a/JavaScriptCore/wtf/Threading.h b/JavaScriptCore/wtf/Threading.h index 72c242f..2a2e9c4 100644 --- a/JavaScriptCore/wtf/Threading.h +++ b/JavaScriptCore/wtf/Threading.h @@ -73,8 +73,8 @@ #include <windows.h> #elif PLATFORM(DARWIN) #include <libkern/OSAtomic.h> -#elif defined ANDROID -#include "cutils/atomic.h" +#elif PLATFORM(ANDROID) +#include <cutils/atomic.h> #elif COMPILER(GCC) #if (__GNUC__ > 4) || ((__GNUC__ == 4) && (__GNUC_MINOR__ >= 2)) #include <ext/atomicity.h> @@ -86,7 +86,7 @@ #if USE(PTHREADS) #include <pthread.h> #elif PLATFORM(GTK) -#include <wtf/GOwnPtr.h> +#include <wtf/gtk/GOwnPtr.h> typedef struct _GMutex GMutex; typedef struct _GCond GCond; #endif @@ -221,28 +221,28 @@ private: #define WTF_USE_LOCKFREE_THREADSAFESHARED 1 #if COMPILER(MINGW) || COMPILER(MSVC7) || PLATFORM(WINCE) -inline void atomicIncrement(int* addend) { InterlockedIncrement(reinterpret_cast<long*>(addend)); } +inline int atomicIncrement(int* addend) { return InterlockedIncrement(reinterpret_cast<long*>(addend)); } inline int atomicDecrement(int* addend) { return InterlockedDecrement(reinterpret_cast<long*>(addend)); } #else -inline void atomicIncrement(int volatile* addend) { InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); } +inline int atomicIncrement(int volatile* addend) { return InterlockedIncrement(reinterpret_cast<long volatile*>(addend)); } inline int atomicDecrement(int volatile* addend) { return InterlockedDecrement(reinterpret_cast<long volatile*>(addend)); } #endif #elif PLATFORM(DARWIN) #define WTF_USE_LOCKFREE_THREADSAFESHARED 1 -inline void atomicIncrement(int volatile* addend) { OSAtomicIncrement32Barrier(const_cast<int*>(addend)); } +inline int atomicIncrement(int volatile* addend) { return OSAtomicIncrement32Barrier(const_cast<int*>(addend)); } inline int atomicDecrement(int volatile* addend) { return OSAtomicDecrement32Barrier(const_cast<int*>(addend)); } -#elif defined ANDROID +#elif PLATFORM(ANDROID) -inline void atomicIncrement(int volatile* addend) { android_atomic_inc(addend); } +inline int atomicIncrement(int volatile* addend) { return android_atomic_inc(addend); } inline int atomicDecrement(int volatile* addend) { return android_atomic_dec(addend); } -#elif COMPILER(GCC) +#elif COMPILER(GCC) && !PLATFORM(SPARC64) // sizeof(_Atomic_word) != sizeof(int) on sparc64 gcc #define WTF_USE_LOCKFREE_THREADSAFESHARED 1 -inline void atomicIncrement(int volatile* addend) { __gnu_cxx::__atomic_add(addend, 1); } +inline int atomicIncrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, 1) + 1; } inline int atomicDecrement(int volatile* addend) { return __gnu_cxx::__exchange_and_add(addend, -1) - 1; } #endif @@ -259,15 +259,8 @@ public: #if USE(LOCKFREE_THREADSAFESHARED) atomicIncrement(&m_refCount); #else -#if defined ANDROID // avoid constructing a class to avoid two mystery crashes - m_mutex.lock(); -#else MutexLocker locker(m_mutex); -#endif ++m_refCount; -#if defined ANDROID - m_mutex.unlock(); -#endif #endif } @@ -294,16 +287,9 @@ protected: #else int refCount; { -#if defined ANDROID // avoid constructing a class to avoid two mystery crashes - m_mutex.lock(); -#else MutexLocker locker(m_mutex); -#endif --m_refCount; refCount = m_refCount; -#if defined ANDROID - m_mutex.unlock(); -#endif } if (refCount <= 0) return true; @@ -350,6 +336,11 @@ using WTF::ThreadCondition; using WTF::ThreadIdentifier; using WTF::ThreadSafeShared; +#if USE(LOCKFREE_THREADSAFESHARED) +using WTF::atomicDecrement; +using WTF::atomicIncrement; +#endif + using WTF::createThread; using WTF::currentThread; using WTF::isMainThread; diff --git a/JavaScriptCore/wtf/ThreadingPthreads.cpp b/JavaScriptCore/wtf/ThreadingPthreads.cpp index ea09a1f..fe7b26a 100644 --- a/JavaScriptCore/wtf/ThreadingPthreads.cpp +++ b/JavaScriptCore/wtf/ThreadingPthreads.cpp @@ -39,8 +39,11 @@ #include "StdLibExtras.h" #include "UnusedParam.h" #include <errno.h> + +#if !COMPILER(MSVC) #include <limits.h> #include <sys/time.h> +#endif #if PLATFORM(ANDROID) #include "jni_utility.h" @@ -53,7 +56,7 @@ typedef HashMap<ThreadIdentifier, pthread_t> ThreadMap; static Mutex* atomicallyInitializedStaticMutex; #if !PLATFORM(DARWIN) || PLATFORM(CHROMIUM) -static ThreadIdentifier mainThreadIdentifier; // The thread that was the first to call initializeThreading(), which must be the main thread. +static pthread_t mainThread; // The thread that was the first to call initializeThreading(), which must be the main thread. #endif static Mutex& threadMapMutex() @@ -69,7 +72,7 @@ void initializeThreading() threadMapMutex(); initializeRandomNumberGenerator(); #if !PLATFORM(DARWIN) || PLATFORM(CHROMIUM) - mainThreadIdentifier = currentThread(); + mainThread = pthread_self(); #endif initializeMainThread(); } @@ -184,7 +187,7 @@ ThreadIdentifier createThreadInternal(ThreadFunction entryPoint, void* data, con void setThreadNameInternal(const char* threadName) { -#if PLATFORM(DARWIN) && !defined(BUILDING_ON_TIGER) && !defined(BUILDING_ON_LEOPARD) && !PLATFORM(IPHONE) +#if HAVE(PTHREAD_SETNAME_NP) pthread_setname_np(threadName); #else UNUSED_PARAM(threadName); @@ -229,7 +232,7 @@ bool isMainThread() #if PLATFORM(DARWIN) && !PLATFORM(CHROMIUM) return pthread_main_np(); #else - return currentThread() == mainThreadIdentifier; + return pthread_equal(pthread_self(), mainThread); #endif } @@ -269,7 +272,6 @@ void Mutex::unlock() } #if HAVE(PTHREAD_RWLOCK) - ReadWriteLock::ReadWriteLock() { pthread_rwlock_init(&m_readWriteLock, NULL); diff --git a/JavaScriptCore/wtf/TypeTraits.h b/JavaScriptCore/wtf/TypeTraits.h index 6ce6a3e..9e75e7a 100644 --- a/JavaScriptCore/wtf/TypeTraits.h +++ b/JavaScriptCore/wtf/TypeTraits.h @@ -155,7 +155,7 @@ namespace WTF { typedef IntegralConstant<bool, true> true_type; typedef IntegralConstant<bool, false> false_type; -#if defined(_MSC_VER) && (_MSC_VER >= 1400) +#if defined(_MSC_VER) && (_MSC_VER >= 1400) && !defined(__INTEL_COMPILER) // VC8 (VS2005) and later have built-in compiler support for HasTrivialConstructor / HasTrivialDestructor, // but for some unexplained reason it doesn't work on built-in types. template <typename T> struct HasTrivialConstructor : public IntegralConstant<bool, __has_trivial_constructor(T)>{ }; diff --git a/JavaScriptCore/wtf/Vector.h b/JavaScriptCore/wtf/Vector.h index 7cba4e4..decc9c9 100644 --- a/JavaScriptCore/wtf/Vector.h +++ b/JavaScriptCore/wtf/Vector.h @@ -63,8 +63,15 @@ namespace WTF { template <size_t size> struct AlignedBuffer<size, 32> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 32); }; template <size_t size> struct AlignedBuffer<size, 64> { WTF_ALIGNED(AlignedBufferChar, buffer[size], 64); }; + template <size_t size, size_t alignment> + void swap(AlignedBuffer<size, alignment>& a, AlignedBuffer<size, alignment>& b) + { + for (size_t i = 0; i < size; ++i) + std::swap(a.buffer[i], b.buffer[i]); + } + template <bool needsDestruction, typename T> - class VectorDestructor; + struct VectorDestructor; template<typename T> struct VectorDestructor<false, T> @@ -83,7 +90,7 @@ namespace WTF { }; template <bool needsInitialization, bool canInitializeWithMemset, typename T> - class VectorInitializer; + struct VectorInitializer; template<bool ignore, typename T> struct VectorInitializer<false, ignore, T> @@ -111,7 +118,7 @@ namespace WTF { }; template <bool canMoveWithMemcpy, typename T> - class VectorMover; + struct VectorMover; template<typename T> struct VectorMover<false, T> @@ -155,7 +162,7 @@ namespace WTF { }; template <bool canCopyWithMemcpy, typename T> - class VectorCopier; + struct VectorCopier; template<typename T> struct VectorCopier<false, T> @@ -180,7 +187,7 @@ namespace WTF { }; template <bool canFillWithMemset, typename T> - class VectorFiller; + struct VectorFiller; template<typename T> struct VectorFiller<false, T> @@ -205,7 +212,7 @@ namespace WTF { }; template<bool canCompareWithMemcmp, typename T> - class VectorComparer; + struct VectorComparer; template<typename T> struct VectorComparer<false, T> @@ -404,6 +411,27 @@ namespace WTF { Base::deallocateBuffer(bufferToDeallocate); } + void swap(VectorBuffer<T, inlineCapacity>& other) + { + if (buffer() == inlineBuffer() && other.buffer() == other.inlineBuffer()) { + WTF::swap(m_inlineBuffer, other.m_inlineBuffer); + std::swap(m_capacity, other.m_capacity); + } else if (buffer() == inlineBuffer()) { + m_buffer = other.m_buffer; + other.m_buffer = other.inlineBuffer(); + WTF::swap(m_inlineBuffer, other.m_inlineBuffer); + std::swap(m_capacity, other.m_capacity); + } else if (other.buffer() == other.inlineBuffer()) { + other.m_buffer = m_buffer; + m_buffer = inlineBuffer(); + WTF::swap(m_inlineBuffer, other.m_inlineBuffer); + std::swap(m_capacity, other.m_capacity); + } else { + std::swap(m_buffer, other.m_buffer); + std::swap(m_capacity, other.m_capacity); + } + } + void restoreInlineBufferIfNeeded() { if (m_buffer) diff --git a/JavaScriptCore/wtf/VectorTraits.h b/JavaScriptCore/wtf/VectorTraits.h index 7974b9a..bf77878 100644 --- a/JavaScriptCore/wtf/VectorTraits.h +++ b/JavaScriptCore/wtf/VectorTraits.h @@ -21,6 +21,7 @@ #ifndef WTF_VectorTraits_h #define WTF_VectorTraits_h +#include "OwnPtr.h" #include "RefPtr.h" #include "TypeTraits.h" #include <utility> @@ -31,7 +32,7 @@ using std::pair; namespace WTF { template<bool isPod, typename T> - class VectorTraitsBase; + struct VectorTraitsBase; template<typename T> struct VectorTraitsBase<false, T> @@ -71,11 +72,14 @@ namespace WTF { static const bool canCompareWithMemcmp = true; }; - // we know RefPtr is simple enough that initializing to 0 and moving with memcpy + // we know OwnPtr and RefPtr are simple enough that initializing to 0 and moving with memcpy // (and then not destructing the original) will totally work template<typename P> struct VectorTraits<RefPtr<P> > : SimpleClassVectorTraits { }; - + + template<typename P> + struct VectorTraits<OwnPtr<P> > : SimpleClassVectorTraits { }; + template<typename P> struct VectorTraits<std::auto_ptr<P> > : SimpleClassVectorTraits { }; diff --git a/JavaScriptCore/wtf/android/AndroidThreading.h b/JavaScriptCore/wtf/android/AndroidThreading.h new file mode 100644 index 0000000..27f548c --- /dev/null +++ b/JavaScriptCore/wtf/android/AndroidThreading.h @@ -0,0 +1,39 @@ +/* + * Copyright 2009, The Android Open Source Project + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR + * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, + * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, + * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR + * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY + * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef AndroidThreading_h +#define AndroidThreading_h + +namespace WTF { + +// An interface to the embedding layer, which provides threading support. +class AndroidThreading { +public: + static void scheduleDispatchFunctionsOnMainThread(); +}; + +} // namespace WTF + +#endif // AndroidThreading_h diff --git a/JavaScriptCore/wtf/android/MainThreadAndroid.cpp b/JavaScriptCore/wtf/android/MainThreadAndroid.cpp index ab0d3bf..5e5f7b1 100644 --- a/JavaScriptCore/wtf/android/MainThreadAndroid.cpp +++ b/JavaScriptCore/wtf/android/MainThreadAndroid.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2008, The Android Open Source Project + * Copyright 2009, The Android Open Source Project * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -13,7 +13,7 @@ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``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 + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR @@ -26,25 +26,17 @@ #include "config.h" #include "MainThread.h" -#include "jni/JavaSharedClient.h" - -using namespace android; +#include "AndroidThreading.h" namespace WTF { -// Callback in the main thread. -static void timeoutFired(void* ) -{ - dispatchFunctionsFromMainThread(); -} - void initializeMainThreadPlatform() { } void scheduleDispatchFunctionsOnMainThread() { - JavaSharedClient::EnqueueFunctionPtr(timeoutFired, 0); + AndroidThreading::scheduleDispatchFunctionsOnMainThread(); } -} +} // namespace WTF diff --git a/JavaScriptCore/wtf/dtoa.cpp b/JavaScriptCore/wtf/dtoa.cpp index d75c17a..edcb82b 100644 --- a/JavaScriptCore/wtf/dtoa.cpp +++ b/JavaScriptCore/wtf/dtoa.cpp @@ -140,7 +140,6 @@ #else #define NO_ERRNO #endif -#include <float.h> #include <math.h> #include <stdint.h> #include <stdlib.h> @@ -148,6 +147,7 @@ #include <wtf/AlwaysInline.h> #include <wtf/Assertions.h> #include <wtf/FastMalloc.h> +#include <wtf/MathExtras.h> #include <wtf/Vector.h> #include <wtf/Threading.h> @@ -1869,7 +1869,7 @@ static ALWAYS_INLINE int quorem(BigInt& b, BigInt& S) * calculation. */ -void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rve) +void dtoa(DtoaBuffer result, double dd, int ndigits, int* decpt, int* sign, char** rve) { /* Arguments ndigits, decpt, sign are similar to those @@ -1908,16 +1908,23 @@ void dtoa(char* result, double dd, int ndigits, int* decpt, int* sign, char** rv { /* Infinity or NaN */ *decpt = 9999; - if (!word1(&u) && !(word0(&u) & 0xfffff)) + if (!word1(&u) && !(word0(&u) & 0xfffff)) { strcpy(result, "Infinity"); - else + if (rve) + *rve = result + 8; + } else { strcpy(result, "NaN"); + if (rve) + *rve = result + 3; + } return; } if (!dval(&u)) { *decpt = 1; result[0] = '0'; result[1] = '\0'; + if (rve) + *rve = result + 1; return; } @@ -2376,4 +2383,83 @@ ret: *rve = s; } +static ALWAYS_INLINE void append(char*& next, const char* src, unsigned size) +{ + for (unsigned i = 0; i < size; ++i) + *next++ = *src++; +} + +void doubleToStringInJavaScriptFormat(double d, DtoaBuffer buffer, unsigned* resultLength) +{ + ASSERT(buffer); + + // avoid ever printing -NaN, in JS conceptually there is only one NaN value + if (isnan(d)) { + append(buffer, "NaN", 3); + if (resultLength) + *resultLength = 3; + return; + } + // -0 -> "0" + if (!d) { + buffer[0] = '0'; + if (resultLength) + *resultLength = 1; + return; + } + + int decimalPoint; + int sign; + + DtoaBuffer result; + char* resultEnd = 0; + WTF::dtoa(result, d, 0, &decimalPoint, &sign, &resultEnd); + int length = resultEnd - result; + + char* next = buffer; + if (sign) + *next++ = '-'; + + if (decimalPoint <= 0 && decimalPoint > -6) { + *next++ = '0'; + *next++ = '.'; + for (int j = decimalPoint; j < 0; j++) + *next++ = '0'; + append(next, result, length); + } else if (decimalPoint <= 21 && decimalPoint > 0) { + if (length <= decimalPoint) { + append(next, result, length); + for (int j = 0; j < decimalPoint - length; j++) + *next++ = '0'; + } else { + append(next, result, decimalPoint); + *next++ = '.'; + append(next, result + decimalPoint, length - decimalPoint); + } + } else if (result[0] < '0' || result[0] > '9') + append(next, result, length); + else { + *next++ = result[0]; + if (length > 1) { + *next++ = '.'; + append(next, result + 1, length - 1); + } + + *next++ = 'e'; + *next++ = (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) + *next++ = static_cast<char>('0' + exponential / 100); + if (exponential >= 10) + *next++ = static_cast<char>('0' + (exponential % 100) / 10); + *next++ = static_cast<char>('0' + exponential % 10); + } + if (resultLength) + *resultLength = next - buffer; +} + } // namespace WTF diff --git a/JavaScriptCore/wtf/dtoa.h b/JavaScriptCore/wtf/dtoa.h index cbec7c7..6127f53 100644 --- a/JavaScriptCore/wtf/dtoa.h +++ b/JavaScriptCore/wtf/dtoa.h @@ -30,8 +30,18 @@ namespace WTF { extern WTF::Mutex* s_dtoaP5Mutex; double strtod(const char* s00, char** se); - void dtoa(char* result, double d, int ndigits, int* decpt, int* sign, char** rve); + + typedef char DtoaBuffer[80]; + void dtoa(DtoaBuffer result, double d, int ndigits, int* decpt, int* sign, char** rve); + + // dtoa() for ECMA-262 'ToString Applied to the Number Type.' + // The *resultLength will have the length of the resultant string in bufer. + // The resultant string isn't terminated by 0. + void doubleToStringInJavaScriptFormat(double, DtoaBuffer, unsigned* resultLength); } // namespace WTF +using WTF::DtoaBuffer; +using WTF::doubleToStringInJavaScriptFormat; + #endif // WTF_dtoa_h diff --git a/JavaScriptCore/wtf/GOwnPtr.cpp b/JavaScriptCore/wtf/gtk/GOwnPtr.cpp index 432885f..8999962 100644 --- a/JavaScriptCore/wtf/GOwnPtr.cpp +++ b/JavaScriptCore/wtf/gtk/GOwnPtr.cpp @@ -19,6 +19,8 @@ #include "config.h" #include "GOwnPtr.h" +#include <glib.h> + namespace WTF { template <> void freeOwnedGPtr<GError>(GError* ptr) diff --git a/JavaScriptCore/wtf/gtk/GOwnPtr.h b/JavaScriptCore/wtf/gtk/GOwnPtr.h new file mode 100644 index 0000000..ad2c30e --- /dev/null +++ b/JavaScriptCore/wtf/gtk/GOwnPtr.h @@ -0,0 +1,146 @@ +/* + * Copyright (C) 2006, 2007 Apple Inc. All rights reserved. + * Copyright (C) 2008 Collabora Ltd. + * + * 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 GOwnPtr_h +#define GOwnPtr_h + +#include <algorithm> +#include <wtf/Assertions.h> +#include <wtf/Noncopyable.h> + +// Forward delcarations at this point avoid the need to include GLib includes +// in WTF headers. +typedef struct _GError GError; +typedef struct _GList GList; +typedef struct _GCond GCond; +typedef struct _GMutex GMutex; +typedef struct _GPatternSpec GPatternSpec; +typedef struct _GDir GDir; +typedef struct _GHashTable GHashTable; +extern "C" void g_free(void*); + +namespace WTF { + +template <typename T> inline void freeOwnedGPtr(T* ptr); +template<> void freeOwnedGPtr<GError>(GError*); +template<> void freeOwnedGPtr<GList>(GList*); +template<> void freeOwnedGPtr<GCond>(GCond*); +template<> void freeOwnedGPtr<GMutex>(GMutex*); +template<> void freeOwnedGPtr<GPatternSpec>(GPatternSpec*); +template<> void freeOwnedGPtr<GDir>(GDir*); +template<> void freeOwnedGPtr<GHashTable>(GHashTable*); + +template <typename T> class GOwnPtr : public Noncopyable { +public: + explicit GOwnPtr(T* ptr = 0) : m_ptr(ptr) { } + ~GOwnPtr() { freeOwnedGPtr(m_ptr); } + + T* get() const { return m_ptr; } + T* release() + { + T* ptr = m_ptr; + m_ptr = 0; + return ptr; + } + + T*& outPtr() + { + ASSERT(!m_ptr); + return m_ptr; + } + + void set(T* ptr) + { + ASSERT(!ptr || m_ptr != ptr); + freeOwnedGPtr(m_ptr); + m_ptr = ptr; + } + + void clear() + { + freeOwnedGPtr(m_ptr); + m_ptr = 0; + } + + T& operator*() const + { + ASSERT(m_ptr); + return *m_ptr; + } + + T* operator->() const + { + ASSERT(m_ptr); + return m_ptr; + } + + bool operator!() const { return !m_ptr; } + + // This conversion operator allows implicit conversion to bool but not to other integer types. + typedef T* GOwnPtr::*UnspecifiedBoolType; + operator UnspecifiedBoolType() const { return m_ptr ? &GOwnPtr::m_ptr : 0; } + + void swap(GOwnPtr& o) { std::swap(m_ptr, o.m_ptr); } + +private: + T* m_ptr; +}; + +template <typename T> inline void swap(GOwnPtr<T>& a, GOwnPtr<T>& b) +{ + a.swap(b); +} + +template <typename T, typename U> inline bool operator==(const GOwnPtr<T>& a, U* b) +{ + return a.get() == b; +} + +template <typename T, typename U> inline bool operator==(T* a, const GOwnPtr<U>& b) +{ + return a == b.get(); +} + +template <typename T, typename U> inline bool operator!=(const GOwnPtr<T>& a, U* b) +{ + return a.get() != b; +} + +template <typename T, typename U> inline bool operator!=(T* a, const GOwnPtr<U>& b) +{ + return a != b.get(); +} + +template <typename T> inline typename GOwnPtr<T>::PtrType getPtr(const GOwnPtr<T>& p) +{ + return p.get(); +} + +template <typename T> inline void freeOwnedGPtr(T* ptr) +{ + g_free(ptr); +} + +} // namespace WTF + +using WTF::GOwnPtr; + +#endif // GOwnPtr_h diff --git a/JavaScriptCore/wtf/haiku/MainThreadHaiku.cpp b/JavaScriptCore/wtf/haiku/MainThreadHaiku.cpp index 4fd7b35..10c4248 100644 --- a/JavaScriptCore/wtf/haiku/MainThreadHaiku.cpp +++ b/JavaScriptCore/wtf/haiku/MainThreadHaiku.cpp @@ -30,6 +30,7 @@ #include "config.h" #include "MainThread.h" +#include "NotImplemented.h" namespace WTF { diff --git a/JavaScriptCore/wtf/unicode/UTF8.cpp b/JavaScriptCore/wtf/unicode/UTF8.cpp index 9e713fe..21d5856 100644 --- a/JavaScriptCore/wtf/unicode/UTF8.cpp +++ b/JavaScriptCore/wtf/unicode/UTF8.cpp @@ -23,6 +23,7 @@ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#include "config.h" #include "UTF8.h" namespace WTF { diff --git a/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp b/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp index a779b36..e20c376 100644 --- a/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp +++ b/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.cpp @@ -19,6 +19,7 @@ * */ +#include "config.h" #include "UnicodeGLib.h" namespace WTF { diff --git a/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h b/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h index c03d3ec..d72e707 100644 --- a/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h +++ b/JavaScriptCore/wtf/unicode/glib/UnicodeGLib.h @@ -26,7 +26,7 @@ #define UnicodeGLib_h #include "UnicodeMacrosFromICU.h" -#include <wtf/GOwnPtr.h> +#include <wtf/gtk/GOwnPtr.h> #include <glib.h> #include <pango/pango.h> @@ -152,6 +152,11 @@ inline bool isArabicChar(UChar32 c) return c >= 0x0600 && c <= 0x06FF; } +inline bool isAlphanumeric(UChar32 c) +{ + return g_unichar_isalnum(c); +} + inline bool isFormatChar(UChar32 c) { return g_unichar_type(c) == G_UNICODE_FORMAT; diff --git a/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h b/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h index 35c6fbf..a2a5c0a 100644 --- a/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h +++ b/JavaScriptCore/wtf/unicode/icu/UnicodeIcu.h @@ -164,6 +164,11 @@ inline bool isArabicChar(UChar32 c) return ublock_getCode(c) == UBLOCK_ARABIC; } +inline bool isAlphanumeric(UChar32 c) +{ + return u_isalnum(c); +} + inline bool isSeparatorSpace(UChar32 c) { return u_charType(c) == U_SPACE_SEPARATOR; diff --git a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h index 1531694..cfd482d 100644 --- a/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h +++ b/JavaScriptCore/wtf/unicode/qt4/UnicodeQt4.h @@ -30,7 +30,6 @@ #include <stdint.h> -#if QT_VERSION >= 0x040300 QT_BEGIN_NAMESPACE namespace QUnicodeTables { struct Properties { @@ -55,10 +54,9 @@ namespace QUnicodeTables { Q_CORE_EXPORT const Properties * QT_FASTCALL properties(ushort ucs2); } QT_END_NAMESPACE -#endif // ugly hack to make UChar compatible with JSChar in API/JSStringRef.h -#if defined(Q_OS_WIN) +#if defined(Q_OS_WIN) || COMPILER(WINSCW) typedef wchar_t UChar; #else typedef uint16_t UChar; @@ -186,8 +184,6 @@ enum CharCategory { }; -#if QT_VERSION >= 0x040300 - // FIXME: handle surrogates correctly in all methods inline UChar32 toLower(UChar32 ch) @@ -406,138 +402,6 @@ inline CharCategory category(UChar32 c) return (CharCategory) U_MASK(QChar::category(c)); } -#else - -inline UChar32 toLower(UChar32 ch) -{ - if (ch > 0xffff) - return ch; - return QChar((unsigned short)ch).toLower().unicode(); -} - -inline int toLower(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) -{ - *error = false; - if (resultLength < srcLength) { - *error = true; - return srcLength; - } - for (int i = 0; i < srcLength; ++i) - result[i] = QChar(src[i]).toLower().unicode(); - return srcLength; -} - -inline UChar32 toUpper(UChar32 ch) -{ - if (ch > 0xffff) - return ch; - return QChar((unsigned short)ch).toUpper().unicode(); -} - -inline int toUpper(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) -{ - *error = false; - if (resultLength < srcLength) { - *error = true; - return srcLength; - } - for (int i = 0; i < srcLength; ++i) - result[i] = QChar(src[i]).toUpper().unicode(); - return srcLength; -} - -inline int toTitleCase(UChar32 c) -{ - if (c > 0xffff) - return c; - return QChar((unsigned short)c).toUpper().unicode(); -} - -inline UChar32 foldCase(UChar32 c) -{ - if (c > 0xffff) - return c; - return QChar((unsigned short)c).toLower().unicode(); -} - -inline int foldCase(UChar* result, int resultLength, const UChar* src, int srcLength, bool* error) -{ - return toLower(result, resultLength, src, srcLength, error); -} - -inline bool isPrintableChar(UChar32 c) -{ - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPrint(); -} - -inline bool isArabicChar(UChar32 c) -{ - return c >= 0x0600 && c <= 0x06FF; -} - -inline bool isSeparatorSpace(UChar32 c) -{ - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Separator_Space; -} - -inline bool isPunct(UChar32 c) -{ - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).isPunct(); -} - -inline bool isLower(UChar32 c) -{ - return (c & 0xffff0000) == 0 && QChar((unsigned short)c).category() == QChar::Letter_Lowercase; -} - -inline UChar32 mirroredChar(UChar32 c) -{ - if (c > 0xffff) - return c; - return QChar(c).mirroredChar().unicode(); -} - -inline uint8_t combiningClass(UChar32 c) -{ - if (c > 0xffff) - return 0; - return QChar((unsigned short)c).combiningClass(); -} - -inline DecompositionType decompositionType(UChar32 c) -{ - if (c > 0xffff) - return DecompositionNone; - return (DecompositionType)QChar(c).decompositionTag(); -} - -inline int umemcasecmp(const UChar* a, const UChar* b, int len) -{ - for (int i = 0; i < len; ++i) { - QChar c1 = QChar(a[i]).toLower(); - QChar c2 = QChar(b[i]).toLower(); - if (c1 != c2) - return c1.unicode() - c2.unicode(); - } - return 0; -} - -inline Direction direction(UChar32 c) -{ - if (c > 0xffff) - return LeftToRight; - return (Direction)QChar(c).direction(); -} - -inline CharCategory category(UChar32 c) -{ - if (c > 0xffff) - return NoCategory; - return (CharCategory) U_MASK(QChar(c).category()); -} - -#endif - } } #endif // WTF_UNICODE_QT4_H diff --git a/JavaScriptCore/wtf/unicode/wince/UnicodeWince.cpp b/JavaScriptCore/wtf/unicode/wince/UnicodeWince.cpp index 966f2a1..2df44f8 100644 --- a/JavaScriptCore/wtf/unicode/wince/UnicodeWince.cpp +++ b/JavaScriptCore/wtf/unicode/wince/UnicodeWince.cpp @@ -19,6 +19,7 @@ * Boston, MA 02110-1301, USA. */ +#include "config.h" #include "UnicodeWince.h" #include <wchar.h> diff --git a/JavaScriptCore/wtf/wince/FastMallocWince.h b/JavaScriptCore/wtf/wince/FastMallocWince.h index 93d9f75..37174f0 100644 --- a/JavaScriptCore/wtf/wince/FastMallocWince.h +++ b/JavaScriptCore/wtf/wince/FastMallocWince.h @@ -1,5 +1,4 @@ /* - * This file is part of the KDE libraries * Copyright (C) 2005, 2006, 2007, 2008 Apple Inc. All rights reserved. * Copyright (C) 2007-2009 Torch Mobile, Inc. All rights reserved * diff --git a/JavaScriptCore/yarr/RegexInterpreter.cpp b/JavaScriptCore/yarr/RegexInterpreter.cpp index b0aae65..d088086 100644 --- a/JavaScriptCore/yarr/RegexInterpreter.cpp +++ b/JavaScriptCore/yarr/RegexInterpreter.cpp @@ -20,7 +20,7 @@ * 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. + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ #include "config.h" @@ -90,7 +90,7 @@ public: : term(0) { } - + void* operator new(size_t, void* where) { return where; @@ -124,7 +124,7 @@ public: subpatternBackup[i] = output[(firstSubpatternId << 1) + i]; output[(firstSubpatternId << 1) + i] = -1; } - + new(getDisjunctionContext(term)) DisjunctionContext(); } @@ -138,7 +138,7 @@ public: for (unsigned i = 0; i < (numNestedSubpatterns << 1); ++i) output[(firstSubpatternId << 1) + i] = subpatternBackup[i]; } - + DisjunctionContext* getDisjunctionContext(ByteTerm& term) { return reinterpret_cast<DisjunctionContext*>(&(subpatternBackup[term.atom.parenthesesDisjunction->m_numSubpatterns << 1])); @@ -208,7 +208,7 @@ public: return input[pos - 1]; return -1; } - + unsigned getPos() { return pos; @@ -218,7 +218,7 @@ public: { pos = p; } - + bool atStart() { return pos == 0; @@ -284,7 +284,7 @@ public: { if (input.atEnd()) return false; - + int ch = input.read(); if (pattern->m_ignoreCase ? ((Unicode::toLower(testChar) == ch) || (Unicode::toUpper(testChar) == ch)) : (testChar == ch)) { @@ -341,7 +341,7 @@ public: return false; } } - + return true; } @@ -606,10 +606,10 @@ public: if (matchDisjunction(term.atom.parenthesesDisjunction, context->getDisjunctionContext(term), true)) return true; - + resetMatches(term, context); - freeParenthesesDisjunctionContext(context); popParenthesesDisjunctionContext(backTrack); + freeParenthesesDisjunctionContext(context); } return false; @@ -910,8 +910,8 @@ public: } } else { resetMatches(term, context); - freeParenthesesDisjunctionContext(context); popParenthesesDisjunctionContext(backTrack); + freeParenthesesDisjunctionContext(context); } if (backTrack->matchAmount) { @@ -946,11 +946,11 @@ public: } return true; } - + // pop a match off the stack resetMatches(term, context); - freeParenthesesDisjunctionContext(context); popParenthesesDisjunctionContext(backTrack); + freeParenthesesDisjunctionContext(context); } return false; @@ -1266,37 +1266,37 @@ public: ByteCompiler(RegexPattern& pattern) : m_pattern(pattern) { - bodyDisjunction = 0; - currentAlternativeIndex = 0; + m_bodyDisjunction = 0; + m_currentAlternativeIndex = 0; } - + BytecodePattern* compile() { regexBegin(m_pattern.m_numSubpatterns, m_pattern.m_body->m_callFrameSize); emitDisjunction(m_pattern.m_body); regexEnd(); - return new BytecodePattern(bodyDisjunction, m_allParenthesesInfo, m_pattern); + return new BytecodePattern(m_bodyDisjunction, m_allParenthesesInfo, m_pattern); } - + void checkInput(unsigned count) { - bodyDisjunction->terms.append(ByteTerm::CheckInput(count)); + m_bodyDisjunction->terms.append(ByteTerm::CheckInput(count)); } void assertionBOL(int inputPosition) { - bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition)); + m_bodyDisjunction->terms.append(ByteTerm::BOL(inputPosition)); } void assertionEOL(int inputPosition) { - bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition)); + m_bodyDisjunction->terms.append(ByteTerm::EOL(inputPosition)); } void assertionWordBoundary(bool invert, int inputPosition) { - bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition)); + m_bodyDisjunction->terms.append(ByteTerm::WordBoundary(invert, inputPosition)); } void atomPatternCharacter(UChar ch, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) @@ -1304,60 +1304,60 @@ public: if (m_pattern.m_ignoreCase) { UChar lo = Unicode::toLower(ch); UChar hi = Unicode::toUpper(ch); - + if (lo != hi) { - bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType)); + m_bodyDisjunction->terms.append(ByteTerm(lo, hi, inputPosition, frameLocation, quantityCount, quantityType)); return; } } - bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType)); + m_bodyDisjunction->terms.append(ByteTerm(ch, inputPosition, frameLocation, quantityCount, quantityType)); } - + void atomCharacterClass(CharacterClass* characterClass, bool invert, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) { - bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition)); + m_bodyDisjunction->terms.append(ByteTerm(characterClass, invert, inputPosition)); - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount; - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType; - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; } void atomBackReference(unsigned subpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType) { ASSERT(subpatternId); - bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition)); + m_bodyDisjunction->terms.append(ByteTerm::BackReference(subpatternId, inputPosition)); - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount; - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType; - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].atom.quantityType = quantityType; + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; } void atomParenthesesSubpatternBegin(unsigned subpatternId, bool capture, int inputPosition, unsigned frameLocation, unsigned alternativeFrameLocation) { - int beginTerm = bodyDisjunction->terms.size(); + int beginTerm = m_bodyDisjunction->terms.size(); - bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, inputPosition)); - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; - bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpatternOnceBegin, subpatternId, capture, inputPosition)); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; - m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, currentAlternativeIndex)); - currentAlternativeIndex = beginTerm + 1; + m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); + m_currentAlternativeIndex = beginTerm + 1; } void atomParentheticalAssertionBegin(unsigned subpatternId, bool invert, unsigned frameLocation, unsigned alternativeFrameLocation) { - int beginTerm = bodyDisjunction->terms.size(); + int beginTerm = m_bodyDisjunction->terms.size(); - bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, invert, 0)); - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; - bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); - bodyDisjunction->terms[bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParentheticalAssertionBegin, subpatternId, invert, 0)); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = frameLocation; + m_bodyDisjunction->terms.append(ByteTerm::AlternativeBegin()); + m_bodyDisjunction->terms[m_bodyDisjunction->terms.size() - 1].frameLocation = alternativeFrameLocation; - m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, currentAlternativeIndex)); - currentAlternativeIndex = beginTerm + 1; + m_parenthesesStack.append(ParenthesesStackEntry(beginTerm, m_currentAlternativeIndex)); + m_currentAlternativeIndex = beginTerm + 1; } unsigned popParenthesesStack() @@ -1365,12 +1365,12 @@ public: ASSERT(m_parenthesesStack.size()); int stackEnd = m_parenthesesStack.size() - 1; unsigned beginTerm = m_parenthesesStack[stackEnd].beginTerm; - currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex; + m_currentAlternativeIndex = m_parenthesesStack[stackEnd].savedAlternativeIndex; m_parenthesesStack.shrink(stackEnd); - ASSERT(beginTerm < bodyDisjunction->terms.size()); - ASSERT(currentAlternativeIndex < bodyDisjunction->terms.size()); - + ASSERT(beginTerm < m_bodyDisjunction->terms.size()); + ASSERT(m_currentAlternativeIndex < m_bodyDisjunction->terms.size()); + return beginTerm; } @@ -1387,25 +1387,25 @@ public: void closeAlternative(int beginTerm) { int origBeginTerm = beginTerm; - ASSERT(bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin); - int endIndex = bodyDisjunction->terms.size(); + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeBegin); + int endIndex = m_bodyDisjunction->terms.size(); - unsigned frameLocation = bodyDisjunction->terms[beginTerm].frameLocation; + unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation; - if (!bodyDisjunction->terms[beginTerm].alternative.next) - bodyDisjunction->terms.remove(beginTerm); + if (!m_bodyDisjunction->terms[beginTerm].alternative.next) + m_bodyDisjunction->terms.remove(beginTerm); else { - while (bodyDisjunction->terms[beginTerm].alternative.next) { - beginTerm += bodyDisjunction->terms[beginTerm].alternative.next; - ASSERT(bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction); - bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm; - bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; + while (m_bodyDisjunction->terms[beginTerm].alternative.next) { + beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next; + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeAlternativeDisjunction); + m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm; + m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; } - - bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm; - bodyDisjunction->terms.append(ByteTerm::AlternativeEnd()); - bodyDisjunction->terms[endIndex].frameLocation = frameLocation; + m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm; + + m_bodyDisjunction->terms.append(ByteTerm::AlternativeEnd()); + m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation; } } @@ -1413,46 +1413,46 @@ public: { int beginTerm = 0; int origBeginTerm = 0; - ASSERT(bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin); - int endIndex = bodyDisjunction->terms.size(); + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeBegin); + int endIndex = m_bodyDisjunction->terms.size(); - unsigned frameLocation = bodyDisjunction->terms[beginTerm].frameLocation; + unsigned frameLocation = m_bodyDisjunction->terms[beginTerm].frameLocation; - while (bodyDisjunction->terms[beginTerm].alternative.next) { - beginTerm += bodyDisjunction->terms[beginTerm].alternative.next; - ASSERT(bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction); - bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm; - bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; + while (m_bodyDisjunction->terms[beginTerm].alternative.next) { + beginTerm += m_bodyDisjunction->terms[beginTerm].alternative.next; + ASSERT(m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeBodyAlternativeDisjunction); + m_bodyDisjunction->terms[beginTerm].alternative.end = endIndex - beginTerm; + m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; } - - bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm; - bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd()); - bodyDisjunction->terms[endIndex].frameLocation = frameLocation; + m_bodyDisjunction->terms[beginTerm].alternative.next = origBeginTerm - beginTerm; + + m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeEnd()); + m_bodyDisjunction->terms[endIndex].frameLocation = frameLocation; } void atomParenthesesEnd(bool doInline, unsigned lastSubpatternId, int inputPosition, unsigned frameLocation, unsigned quantityCount, QuantifierType quantityType, unsigned callFrameSize = 0) { unsigned beginTerm = popParenthesesStack(); closeAlternative(beginTerm + 1); - unsigned endTerm = bodyDisjunction->terms.size(); + unsigned endTerm = m_bodyDisjunction->terms.size(); - bool isAssertion = bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin; - bool invertOrCapture = bodyDisjunction->terms[beginTerm].invertOrCapture; - unsigned subpatternId = bodyDisjunction->terms[beginTerm].atom.subpatternId; + bool isAssertion = m_bodyDisjunction->terms[beginTerm].type == ByteTerm::TypeParentheticalAssertionBegin; + bool invertOrCapture = m_bodyDisjunction->terms[beginTerm].invertOrCapture; + unsigned subpatternId = m_bodyDisjunction->terms[beginTerm].atom.subpatternId; - bodyDisjunction->terms.append(ByteTerm(isAssertion ? ByteTerm::TypeParentheticalAssertionEnd : ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, invertOrCapture, inputPosition)); - bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm; - bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm; - bodyDisjunction->terms[endTerm].frameLocation = frameLocation; + m_bodyDisjunction->terms.append(ByteTerm(isAssertion ? ByteTerm::TypeParentheticalAssertionEnd : ByteTerm::TypeParenthesesSubpatternOnceEnd, subpatternId, invertOrCapture, inputPosition)); + m_bodyDisjunction->terms[beginTerm].atom.parenthesesWidth = endTerm - beginTerm; + m_bodyDisjunction->terms[endTerm].atom.parenthesesWidth = endTerm - beginTerm; + m_bodyDisjunction->terms[endTerm].frameLocation = frameLocation; if (doInline) { - bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount; - bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; - bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount; - bodyDisjunction->terms[endTerm].atom.quantityType = quantityType; + m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; + m_bodyDisjunction->terms[endTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[endTerm].atom.quantityType = quantityType; } else { - ByteTerm& parenthesesBegin = bodyDisjunction->terms[beginTerm]; + ByteTerm& parenthesesBegin = m_bodyDisjunction->terms[beginTerm]; ASSERT(parenthesesBegin.type == ByteTerm::TypeParenthesesSubpatternOnceBegin); bool invertOrCapture = parenthesesBegin.invertOrCapture; @@ -1463,26 +1463,26 @@ public: parenthesesDisjunction->terms.append(ByteTerm::SubpatternBegin()); for (unsigned termInParentheses = beginTerm + 1; termInParentheses < endTerm; ++termInParentheses) - parenthesesDisjunction->terms.append(bodyDisjunction->terms[termInParentheses]); + parenthesesDisjunction->terms.append(m_bodyDisjunction->terms[termInParentheses]); parenthesesDisjunction->terms.append(ByteTerm::SubpatternEnd()); - bodyDisjunction->terms.shrink(beginTerm); + m_bodyDisjunction->terms.shrink(beginTerm); m_allParenthesesInfo.append(parenthesesDisjunction); - bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, invertOrCapture, inputPosition)); + m_bodyDisjunction->terms.append(ByteTerm(ByteTerm::TypeParenthesesSubpattern, subpatternId, parenthesesDisjunction, invertOrCapture, inputPosition)); - bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount; - bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; - bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; + m_bodyDisjunction->terms[beginTerm].atom.quantityCount = quantityCount; + m_bodyDisjunction->terms[beginTerm].atom.quantityType = quantityType; + m_bodyDisjunction->terms[beginTerm].frameLocation = frameLocation; } } void regexBegin(unsigned numSubpatterns, unsigned callFrameSize) { - bodyDisjunction = new ByteDisjunction(numSubpatterns, callFrameSize); - bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin()); - bodyDisjunction->terms[0].frameLocation = 0; - currentAlternativeIndex = 0; + m_bodyDisjunction = new ByteDisjunction(numSubpatterns, callFrameSize); + m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeBegin()); + m_bodyDisjunction->terms[0].frameLocation = 0; + m_currentAlternativeIndex = 0; } void regexEnd() @@ -1490,34 +1490,34 @@ public: closeBodyAlternative(); } - void alterantiveBodyDisjunction() + void alternativeBodyDisjunction() { - int newAlternativeIndex = bodyDisjunction->terms.size(); - bodyDisjunction->terms[currentAlternativeIndex].alternative.next = newAlternativeIndex - currentAlternativeIndex; - bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction()); + int newAlternativeIndex = m_bodyDisjunction->terms.size(); + m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex; + m_bodyDisjunction->terms.append(ByteTerm::BodyAlternativeDisjunction()); - currentAlternativeIndex = newAlternativeIndex; + m_currentAlternativeIndex = newAlternativeIndex; } - void alterantiveDisjunction() + void alternativeDisjunction() { - int newAlternativeIndex = bodyDisjunction->terms.size(); - bodyDisjunction->terms[currentAlternativeIndex].alternative.next = newAlternativeIndex - currentAlternativeIndex; - bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction()); + int newAlternativeIndex = m_bodyDisjunction->terms.size(); + m_bodyDisjunction->terms[m_currentAlternativeIndex].alternative.next = newAlternativeIndex - m_currentAlternativeIndex; + m_bodyDisjunction->terms.append(ByteTerm::AlternativeDisjunction()); - currentAlternativeIndex = newAlternativeIndex; + m_currentAlternativeIndex = newAlternativeIndex; } void emitDisjunction(PatternDisjunction* disjunction, unsigned inputCountAlreadyChecked = 0, unsigned parenthesesInputCountAlreadyChecked = 0) { for (unsigned alt = 0; alt < disjunction->m_alternatives.size(); ++alt) { unsigned currentCountAlreadyChecked = inputCountAlreadyChecked; - + if (alt) { if (disjunction == m_pattern.m_body) - alterantiveBodyDisjunction(); + alternativeBodyDisjunction(); else - alterantiveDisjunction(); + alternativeDisjunction(); } PatternAlternative* alternative = disjunction->m_alternatives[alt]; @@ -1586,7 +1586,7 @@ public: case PatternTerm::TypeParentheticalAssertion: { unsigned alternativeFrameLocation = term.inputPosition + RegexStackSpaceForBackTrackInfoParentheticalAssertion; - + atomParentheticalAssertionBegin(term.parentheses.subpatternId, term.invertOrCapture, term.frameLocation, alternativeFrameLocation); emitDisjunction(term.parentheses.disjunction, currentCountAlreadyChecked, 0); atomParenthesesEnd(true, term.parentheses.lastSubpatternId, 0, term.frameLocation, term.quantityCount, term.quantityType); @@ -1599,8 +1599,8 @@ public: private: RegexPattern& m_pattern; - ByteDisjunction* bodyDisjunction; - unsigned currentAlternativeIndex; + ByteDisjunction* m_bodyDisjunction; + unsigned m_currentAlternativeIndex; Vector<ParenthesesStackEntry> m_parenthesesStack; Vector<ByteDisjunction*> m_allParenthesesInfo; }; diff --git a/JavaScriptCore/yarr/RegexInterpreter.h b/JavaScriptCore/yarr/RegexInterpreter.h index a8c122a..48c9a5e 100644 --- a/JavaScriptCore/yarr/RegexInterpreter.h +++ b/JavaScriptCore/yarr/RegexInterpreter.h @@ -280,7 +280,7 @@ struct ByteTerm { } }; -class ByteDisjunction { +class ByteDisjunction : public FastAllocBase { public: ByteDisjunction(unsigned numSubpatterns, unsigned frameSize) : m_numSubpatterns(numSubpatterns) @@ -293,7 +293,7 @@ public: unsigned m_frameSize; }; -struct BytecodePattern { +struct BytecodePattern : FastAllocBase { BytecodePattern(ByteDisjunction* body, Vector<ByteDisjunction*> allParenthesesInfo, RegexPattern& pattern) : m_body(body) , m_ignoreCase(pattern.m_ignoreCase) diff --git a/JavaScriptCore/yarr/RegexJIT.cpp b/JavaScriptCore/yarr/RegexJIT.cpp index 663a524..5ce579a 100644 --- a/JavaScriptCore/yarr/RegexJIT.cpp +++ b/JavaScriptCore/yarr/RegexJIT.cpp @@ -45,35 +45,35 @@ class RegexGenerator : private MacroAssembler { friend void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase, bool multiline); #if PLATFORM(ARM) - static const RegisterID input = ARM::r0; - static const RegisterID index = ARM::r1; - static const RegisterID length = ARM::r2; - static const RegisterID output = ARM::r4; + static const RegisterID input = ARMRegisters::r0; + static const RegisterID index = ARMRegisters::r1; + static const RegisterID length = ARMRegisters::r2; + static const RegisterID output = ARMRegisters::r4; - static const RegisterID regT0 = ARM::r5; - static const RegisterID regT1 = ARM::r6; + static const RegisterID regT0 = ARMRegisters::r5; + static const RegisterID regT1 = ARMRegisters::r6; - static const RegisterID returnRegister = ARM::r0; + static const RegisterID returnRegister = ARMRegisters::r0; #elif PLATFORM(X86) - static const RegisterID input = X86::eax; - static const RegisterID index = X86::edx; - static const RegisterID length = X86::ecx; - static const RegisterID output = X86::edi; + static const RegisterID input = X86Registers::eax; + static const RegisterID index = X86Registers::edx; + static const RegisterID length = X86Registers::ecx; + static const RegisterID output = X86Registers::edi; - static const RegisterID regT0 = X86::ebx; - static const RegisterID regT1 = X86::esi; + static const RegisterID regT0 = X86Registers::ebx; + static const RegisterID regT1 = X86Registers::esi; - static const RegisterID returnRegister = X86::eax; + static const RegisterID returnRegister = X86Registers::eax; #elif PLATFORM(X86_64) - static const RegisterID input = X86::edi; - static const RegisterID index = X86::esi; - static const RegisterID length = X86::edx; - static const RegisterID output = X86::ecx; + static const RegisterID input = X86Registers::edi; + static const RegisterID index = X86Registers::esi; + static const RegisterID length = X86Registers::edx; + static const RegisterID output = X86Registers::ecx; - static const RegisterID regT0 = X86::eax; - static const RegisterID regT1 = X86::ebx; + static const RegisterID regT0 = X86Registers::eax; + static const RegisterID regT1 = X86Registers::ebx; - static const RegisterID returnRegister = X86::eax; + static const RegisterID returnRegister = X86Registers::eax; #endif void optimizeAlternative(PatternAlternative* alternative) @@ -549,11 +549,11 @@ class RegexGenerator : private MacroAssembler { } if (mask) { - load32(BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), character); + load32WithUnalignedHalfWords(BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), character); or32(Imm32(mask), character); state.jumpToBacktrack(branch32(NotEqual, character, Imm32(chPair | mask)), this); } else - state.jumpToBacktrack(branch32(NotEqual, BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), Imm32(chPair)), this); + state.jumpToBacktrack(branch32WithUnalignedHalfWords(NotEqual, BaseIndex(input, index, TimesTwo, state.inputOffset() * sizeof(UChar)), Imm32(chPair)), this); } void generatePatternCharacterFixed(TermGenerationState& state) @@ -1264,7 +1264,7 @@ class RegexGenerator : private MacroAssembler { // complex here in compilation, and in the common case we should end up coallescing the checks. // // FIXME: a nice improvement here may be to stop trying to match sooner, based on the least - // of the minimum-alterantive-lengths. E.g. if I have two alternatives of length 200 and 150, + // of the minimum-alternative-lengths. E.g. if I have two alternatives of length 200 and 150, // and a string of length 100, we'll end up looping index from 0 to 100, checking whether there // is sufficient input to run either alternative (constantly failing). If there had been only // one alternative, or if the shorter alternative had come first, we would have terminated @@ -1289,50 +1289,47 @@ class RegexGenerator : private MacroAssembler { void generateEnter() { #if PLATFORM(X86_64) - push(X86::ebp); - move(stackPointerRegister, X86::ebp); - push(X86::ebx); + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); + push(X86Registers::ebx); #elif PLATFORM(X86) - push(X86::ebp); - move(stackPointerRegister, X86::ebp); + push(X86Registers::ebp); + move(stackPointerRegister, X86Registers::ebp); // TODO: do we need spill registers to fill the output pointer if there are no sub captures? - push(X86::ebx); - push(X86::edi); - push(X86::esi); + push(X86Registers::ebx); + push(X86Registers::edi); + push(X86Registers::esi); // load output into edi (2 = saved ebp + return address). #if COMPILER(MSVC) - loadPtr(Address(X86::ebp, 2 * sizeof(void*)), input); - loadPtr(Address(X86::ebp, 3 * sizeof(void*)), index); - loadPtr(Address(X86::ebp, 4 * sizeof(void*)), length); - loadPtr(Address(X86::ebp, 5 * sizeof(void*)), output); + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), input); + loadPtr(Address(X86Registers::ebp, 3 * sizeof(void*)), index); + loadPtr(Address(X86Registers::ebp, 4 * sizeof(void*)), length); + loadPtr(Address(X86Registers::ebp, 5 * sizeof(void*)), output); #else - loadPtr(Address(X86::ebp, 2 * sizeof(void*)), output); + loadPtr(Address(X86Registers::ebp, 2 * sizeof(void*)), output); #endif #elif PLATFORM(ARM) -#if !PLATFORM_ARM_ARCH(7) - push(ARM::lr); -#endif - push(ARM::r4); - push(ARM::r5); - push(ARM::r6); - move(ARM::r3, output); + push(ARMRegisters::r4); + push(ARMRegisters::r5); + push(ARMRegisters::r6); + move(ARMRegisters::r3, output); #endif } void generateReturn() { #if PLATFORM(X86_64) - pop(X86::ebx); - pop(X86::ebp); + pop(X86Registers::ebx); + pop(X86Registers::ebp); #elif PLATFORM(X86) - pop(X86::esi); - pop(X86::edi); - pop(X86::ebx); - pop(X86::ebp); + pop(X86Registers::esi); + pop(X86Registers::edi); + pop(X86Registers::ebx); + pop(X86Registers::ebp); #elif PLATFORM(ARM) - pop(ARM::r6); - pop(ARM::r5); - pop(ARM::r4); + pop(ARMRegisters::r6); + pop(ARMRegisters::r5); + pop(ARMRegisters::r4); #endif ret(); } @@ -1400,14 +1397,6 @@ void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const } } -int executeRegex(RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize) -{ - if (JSRegExp* fallback = jitObject.getFallback()) - return (jsRegExpExecute(fallback, input, length, start, output, outputArraySize) < 0) ? -1 : output[0]; - - return jitObject.execute(input, start, length, output); -} - }} #endif diff --git a/JavaScriptCore/yarr/RegexJIT.h b/JavaScriptCore/yarr/RegexJIT.h index 5b0df9d..1872f21 100644 --- a/JavaScriptCore/yarr/RegexJIT.h +++ b/JavaScriptCore/yarr/RegexJIT.h @@ -82,7 +82,14 @@ private: }; void jitCompileRegex(JSGlobalData* globalData, RegexCodeBlock& jitObject, const UString& pattern, unsigned& numSubpatterns, const char*& error, bool ignoreCase = false, bool multiline = false); -int executeRegex(RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize); + +inline int executeRegex(RegexCodeBlock& jitObject, const UChar* input, unsigned start, unsigned length, int* output, int outputArraySize) +{ + if (JSRegExp* fallback = jitObject.getFallback()) + return (jsRegExpExecute(fallback, input, length, start, output, outputArraySize) < 0) ? -1 : output[0]; + + return jitObject.execute(input, start, length, output); +} } } // namespace JSC::Yarr diff --git a/JavaScriptCore/yarr/RegexPattern.h b/JavaScriptCore/yarr/RegexPattern.h index a451131..dd7512d 100644 --- a/JavaScriptCore/yarr/RegexPattern.h +++ b/JavaScriptCore/yarr/RegexPattern.h @@ -137,7 +137,7 @@ struct PatternTerm { PatternTerm(unsigned spatternId) : type(TypeBackReference) - , invertOrCapture(invertOrCapture) + , invertOrCapture(false) { subpatternId = spatternId; quantityType = QuantifierFixedCount; |
